snprintf错误。 sizeof的参数与destination相同

gcc 4.8在构建时给我一个错误

#include  #include  static inline void toto(char str[3]) { snprintf(str, sizeof(str), "XX"); } int main(){ char str[3]; toto(str); return 0; } 

这是gcc错误

错误:’snprintf’调用中’sizeof’的参数与目标的表达式相同; 你的意思是提供一个明确的长度?

注意:我使用-Wall -Werror标志将警告转换为错误。

这里有类似的东西在评论中,有人回答了这个问题

“对于固定长度的缓冲区,我通常使用strncpy(dest,src,sizeof(dest)); dest [sizeof(dest)-1] =’\ 0′;这保证了NULL终止,并且比snprintf更麻烦,更不用说了很多人都使用snprintf(dest,sizeof(dest),src);相反,当他们的程序任意崩溃时会非常惊讶。“

但这是错误的:gcc 4.8说

“错误:’strncpy’调用中’sizeof’的参数与目标的表达式相同;你的意思是提供显式长度吗?[-Werror = sizeof-pointer-memaccess]”

在gcc 4.8文档中,他们正在讨论这个问题 :他们说:

-Wall的行为已更改,现在包含新警告标志-Wsizeof-pointer-memaccess。 这可能会导致代码中的新警告与以前版本的GCC一起干净地编译。

例如,

 include string.h struct A { }; int main(void) { A obj; A* p1 = &obj; A p2[10]; memset(p1, 0, sizeof(p1)); // error memset(p1, 0, sizeof(*p1)); // ok, dereferenced memset(p2, 0, sizeof(p2)); // ok, array return 0; } 

提供以下诊断:警告:’void memset(void *,int,size_t)’调用中‘sizeof’的参数与目标的表达式相同; 你是不是要取消引用它? [-Wsizeof-pointer-memaccess] memset(p1,0,sizeof(p1)); // error ^虽然这些警告不会导致编译失败,但是-Wall经常与-Werror一起使用,因此新的警告会变成新的错误。 要修复,要么重写以使用memcpy,要么取消引用有问题的memset调用中的最后一个参数。*

好吧,在他们的例子中,显然代码是错误的,但在我的情况下,使用snprintf / strncpy,我不明白为什么,我认为这是gcc的错误positif错误。 对 ?

谢谢你的帮助

传递给函数时,数组会衰减为指向第一个元素的指针。 那么你有什么

static inline void toto(char str[3]) {..}

不是数组而是指针。

因此,gcc正确警告。

是否在函数参数中指定大小无关紧要:

 static inline void toto(char str[3]) 

 static inline void toto(char str[]) 

 static inline void toto(char *str) 

都是等价的。

在这里阅读: 什么是arrays衰减?

test.c的:

 #include  void bar(char foo[1000]) { printf ("sizeof foo = %d\n", (int)(sizeof foo)); } int main () { char foo[1000]; bar(foo); } 

运行:

 bash $ ./test 4 bash $ 

这就是为什么。

在函数定义中,参数声明:

 static inline void toto(char str[3]) 

不将str声明为数组(C没有数组类型的参数)。 相反,它完全等同于:

 static inline void toto(char *str) 

3被悄然忽略了。

因此sizeof(str)与字符串可以容纳的字符数无关,它只是char*指针的大小。

这是由一条规则引起的,该规则说明用数组类型声明的参数被“调整”为指针类型。 这与在大多数情况下将数组类型的表达式隐式转换(或“衰减”)为指针的规则不同。 这两个规则协同工作,使得处理数组的代码看起来像直接处理数组,当它真正使用指向数组元素的指针时。

C数组和指针之间的关系经常令人困惑。 我建议阅读comp.lang.c FAQ的第6节; 它在解释它方面做得很好。

 static inline void toto(char str[3]) 

定义一个可以采用任何大小数组的函数。 忽略3 ,并将str视为指针(尝试printf("%d\n", sizeof(str)) :在我的机器上,它打印8作为64位指针的大小)。 在这种情况下,编译器实际上是正确的。

Clang在这里给出了一个有用的警告:

 test.c:6:25: warning: sizeof on array function parameter will return size of 'char *' instead of 'char [3]' [-Wsizeof-array-argument] snprintf(str, sizeof(str), "XX");