C 哪一个是最标准的:标准还是标准?

C 哪一个是最标准的:标准还是标准?,c,c11,C,C11,在我当前的项目中,我根据C11标准(使用gcc-std=C11构建)进行编码,并且需要类似于strnlen的东西(strlen的“安全”版本,它返回以0结尾的字符串的长度,但仅限于给定的最大值)。所以我查了一下(例如),似乎C11标准提到了这样一个函数,但名称为strnlen\s 因此,我使用了strnlen\u,但在包含string.h时,它没有定义。另一方面,定义了strnlen,因此我当前的解决方案是使用strnlen,并注明标准名称似乎是strnlen_,但这不是GCC定义的 问题是:我

在我当前的项目中,我根据C11标准(使用
gcc-std=C11
构建)进行编码,并且需要类似于
strnlen
的东西(strlen的“安全”版本,它返回以0结尾的字符串的长度,但仅限于给定的最大值)。所以我查了一下(例如),似乎C11标准提到了这样一个函数,但名称为
strnlen\s

因此,我使用了
strnlen\u
,但在包含
string.h
时,它没有定义。另一方面,定义了
strnlen
,因此我当前的解决方案是使用
strnlen
,并注明标准名称似乎是
strnlen_
,但这不是GCC定义的

问题是:我是否正确地假设
strnlen
是最可移植的名称,或者我该怎么做才能使代码最可移植/标准


注意:微软()实现了两个函数,区别在于<代码> StrnLynIs< /Cuff>检查字符串指针是否为代码> null <代码>,并在代码中返回<代码> 0代码>代码,而代码> StrnLeN</代码>没有这样的检查。

字符串是C++头和字符串。h是C标题(至少与GCC)。斯特伦斯(afaik)是一家公司。你说得对,斯特伦会更标准。如果需要字节计数,也可以使用memchr。就@Basile而言,如果你需要字符数,你需要一些UTF-8感知的东西

问题是:我是否正确地假设strnlen是最可移植的名称,或者我该如何使代码最可移植/标准

不,它根本不是便携式的。它从来都不是C语言的一部分。它包含在POSIX中,这并不意味着什么

我可以想象为什么这个函数在标准中不存在,可能是因为当我们已经有
memchr(str,'\0',max)时,它是多余的

strnlen_s
是C11附录K中可选边界检查接口的一部分。整个章节结果是一个巨大的失败,几乎没有编译器实现它。Microsoft具有类似的命名函数,但它们有时不兼容。所以我假设所有的
\u
函数都是完全不可移植的

因此,请不要使用这两种方法,使用
memchr
strlen


编辑

如果出于某种原因您必须自己实现
strnlen
,那么我建议您:

#include <string.h>

size_t strnlength (const char* s, size_t n) 
{ 
  const char* found = memchr(s, '\0', n); 
  return found ? (size_t)(found-s) : n; 
}
#包括
大小字符串长度(常量字符*s,大小字符串n)
{ 
const char*found=memchr(s,'\0',n);
返回发现?(大小_t)(发现-s):n;
}
strnlen_s()
在C11版开始的C标准附录K中规定。本附件未得到广泛实施,甚至微软的实施也未完全符合规定的版本。语义被扭曲,特别是在错误处理方面。我建议不要使用它

strnlen()
是POSIX.1-2008中指定的一个简单函数,可在许多平台上使用。在不提供此功能的平台上很容易实现:

#include <string.h>

size_t strnlen(const char *s, size_t n) {
    size_t i;
    for (i = 0; i < n && s[i] != '\0'; i++)
        continue;
    return i;
}
#包括
大小标准(常量字符*s,大小标准){
尺寸i;
对于(i=0;i
问题是:我是否正确地假设
strnlen
是最可移植的名称,或者我该怎么做才能使代码最可移植/标准

对于C,
strnlen
是可以的,因为名称没有保留。它不是标准的一部分,所以您可以添加它

,因此您可能需要使用其他名称

strnlen_s
与K.3.7.4.4 strnlen_的函数冲突,并且有一段有争议的历史,您可能不希望将代码绑定到其中。避免将函数命名为strnlen\u s()


我将避免使用任何一个添加了两个名称的函数将名称联合到公共库:形式化的名称和宏不太可能冲突

size_t nielsen_strnlen(const char *s, size_t maxsize);
#define slength nielsen_strnlen
或者直接去做一些不太可能发生碰撞的事情

size_t nstrnlen(const char *s, size_t maxsize);

更深层次:OP似乎希望使用标准C库(或当前版本)之外的流行函数,但在将代码移植到其他系统时可能可用。OP希望提供“如果不可用,请使用我的代码”功能

走路要小心

我会使用宏(或包装函数)

。。。然后调用
slenth()

当OP的代码版本与期望的(今天和明天)不完全一样时,或者因为它不是标准的,各种实现都会有所不同——在实现上有一点不同。为了减轻,考虑宏或函数包装器间接。
次要问题:参数顺序和潜在问题


在2021年,您可以使用或@BasileStarynkevitch,这对于许多需要了解UTF的应用程序来说是一个很好的观点。我知道UTF,但我当前的应用程序不需要。顺便说一下,你的“UTF-8无处不在”链接中缺少了一个“y”。是的,合适的网站是
memchr
是一个不错的选择。在像我这样的情况下就不太方便了(字符串有固定大小的缓冲区,只有当它小于缓冲区大小时才需要以0结尾)。可能我最方便的选择是编写自己的“
strnlen
”,可能会包装对
memchr
的调用。编译器不实现
\u
函数的原因是什么?为什么它是可选的?@nielsen或干脆不包装它,而是让代码可读。编写
char*result=memchr(str,'\0',n)并不是一项巨大的工作;if(result){ptrdiff_t index=str-result;}
。不管你做什么,你都需要检查结果。@AyxanHaqverdili,明白了。@Lundin是的,但在我的情况下,这要多一些。类似于:
char*result=memchr(str,'\0',n);如果(结果){size=result-str;}否则{size=n;}
size=(结果)?结果:str:n#if ON_SYSTEM_WITH_strnlen
  #define slength strnlen
#else
  #define slength nielsen_strnlen
#endif   
size_t foo1(const char *s, size_t maxsize);

// arranged such that the size of an array appears before the array. 
size_t foo2(size_t maxsize, const char *s);
size_t foo3(size_t maxsize, const char s[maxsize]);