ramone
ramone

Reputation: 266

snprintf error. argument to sizeof is the same as destination

gcc 4.8 give me an error when I build

#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;
}

Here is the gcc error

error: argument to ‘sizeof’ in ‘snprintf’ call is the same expression as the destination; did you mean to provide an explicit length?

Note: I m using -Wall -Werror flags which convert warning to error.

There is something similar here In a comment, someone answered this

"For fixed length buffers, I usually use strncpy(dest, src, sizeof(dest)); dest[sizeof(dest)-1] = '\0'; That guarantees NULL termination and is just less hassle than snprintf not to mention that a lot of people use snprintf(dest, sizeof(dest), src); instead and are very surprised when their programs crash arbitrarily."

But this is wrong: gcc 4.8 say

"error: argument to ‘sizeof’ in ‘strncpy’ call is the same expression as the destination; did you mean to provide an explicit length? [-Werror=sizeof-pointer-memaccess]"

in gcc 4.8 documentation, they are talking about this issue: they say:

The behavior of -Wall has changed and now includes the new warning flag -Wsizeof-pointer-memaccess. This may result in new warnings in code that compiled cleanly with previous versions of GCC.

For example,

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;
}

Gives the following diagnostic: warning: argument to ‘sizeof’ in ‘void memset(void*, int, size_t)’ call is the same expression as the destination; did you mean to dereference it? [-Wsizeof-pointer-memaccess] memset(p1, 0, sizeof(p1)); // error ^ Although these warnings will not result in compilation failure, often -Wall is used in conjunction with -Werror and as a result, new warnings are turned into new errors. To fix, either re-write to use memcpy or dereference the last argument in the offending memset call.*

Well, in their example, it's obvious the code was wrong, but in my case, with snprintf/strncpy, I dont see why, and I think it's a false positif error of gcc. Right ?

thanks for your help

Upvotes: 16

Views: 25725

Answers (4)

Keith Thompson
Keith Thompson

Reputation: 263267

In your function definition, the parameter declaration:

static inline void toto(char str[3])

does not declare str as an array (C doesn't have parameters of array type). Rather, it's exactly equivalent to:

static inline void toto(char *str)

The 3 is quietly ignored.

So sizeof(str) has nothing to do with the number of characters the string can hold, it's simply the size of a char* pointer.

This results from a rule that says a parameter declared with an array type is "adjusted" to be of pointer type. This is distinct from the rule that says expressions of array type are implicitly converted (or "decay") to pointers in most contexts. The two rules work together to make code that deals with arrays seem like it's dealing with the arrays directly, when it's really working with pointers to elements of the arrays.

The relationship between C arrays and pointers is often confusing. I recommend reading section 6 of the comp.lang.c FAQ; it does a very good job of explaining it.

Upvotes: 3

P.P
P.P

Reputation: 121387

An array decays into a pointer to the first element when you passed to a function. So what you have in

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

is not an array but a pointer.

Hence, gcc rightly warns.

Whether you specify the size in the function parameter or not doesn't matter as:

static inline void toto(char str[3])

and

static inline void toto(char str[])

and

static inline void toto(char *str)

are all equivalent.

Read here on this: what is array decaying?

Upvotes: 14

nneonneo
nneonneo

Reputation: 179422

static inline void toto(char str[3])

defines a function that can take an array of any size. The 3 is ignored, and str is treated as a pointer (try printf("%d\n", sizeof(str)): on my machine, it prints 8 for the size of a 64-bit pointer). The compiler is actually right in this case.

Clang gives a useful warning here:

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"); 

Upvotes: 2

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

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);
}

running:

bash $ ./test
4
bash $

That's why.

Upvotes: 7

Related Questions