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

时间:2013-10-05 20:25:40

标签: c gcc printf

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

#include <string.h>
#include <stdio.h>

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标志将警告转换为错误。

There is something similar here 在评论中,有人回答了这个问题

“对于固定长度的缓冲区,我通常使用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]”

in gcc 4.8 documentation, they are talking about this issue: 他们说:

-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'的参数'call是与目标相同的表达式;你是不是要取消引用它? [-Wsizeof指针-memaccess]   memset(p1,0,sizeof(p1)); //错误                        ^ 虽然这些警告不会导致编译失败,但通常将-Wall与-Werror结合使用,因此新警告会变成新错误。 要修复,要么重写要使用memcpy,要么取消引用有问题的memset调用中的最后一个参数。*

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

感谢您的帮助

4 个答案:

答案 0 :(得分:9)

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

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)

都是等价的。

请阅读此处:what is array decaying?

答案 1 :(得分:4)

test.c的:

#include <stdio.h>

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

int main ()
{
    char foo[1000];
    bar(foo);
}

运行:

bash $ ./test
4
bash $

这就是原因。

答案 2 :(得分:3)

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

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节;它很好地解释了它。

答案 3 :(得分:2)

static inline void toto(char str[3])

定义了一个可以采用任何大小的数组的函数。 3被忽略,str被视为指针(try printf("%d\n", sizeof(str)):在我的机器上,它打印出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");