Same expression as the destination warning when using snprintf
(I've seen questions 19202368, 40095973 and 1775403)
I have this:
char data[32];
memset(data, '\0', sizeof(data));
snprintf(data, sizeof(data), "%s - %d", aCharArray != NULL ? aCharArray : "", anInt);
which yields this warning when compiling on some compilers/architectures:
warning: argument to 'sizeof' in 'int snprintf(char*, size_t, const char*, ...)' call is the same expression as the destination; did you mean to provide an explicit length? [-Wsizeof-pointer-memaccess]
Both aCharArray
and anInt
may be local to the function or passed as arguments. This is a generic example and this is the generic approach I use (using memset
to initialize and preferring snprintf
to sprintf
). I know that if data
is local I can use the same size I used to declare it but I prefer to only specify the size in the declaration, once; this way it's easier to change in the future.
Also, snprintf
will avoid overflows and put the \0
at the end. strlen
will work for a char*
passed as argument to the function but it'll be pointless on a freshly initialized or empty (i.e. ""
) char[]
.
So, I'm not providing the string length as it may be 0, but I do want to provide the array's size.
Is this approach correct or am I missing some caveat?
On a side note, what's the compiler flag to identify switched parameters? I.e., using the above:
snprintf(data, sizeof(data), "%s - %d", anInt, aCharArray);
2 answers
-
answered 2022-05-02 16:16
Dave Meehan
I think it is warning you that
data
(as used in first param) is the same as data in thesizeof
, and thatdata
could be a pointer, not an array (depending on scope).When it's an array you will get
sizeof(char) * count
of elements, but if it's a pointer, you will getsizeof(char *)
.This is a common source of bugs, partly because it is common to see expressions like
sizeof(buffer) / sizeof(buffer[0])
to get the maximum number of elements in an array. It will compile whether buffer ischar buffer[n]
orchar *buffer
, but the result is different.Check your compiler docs to see how to suppress specific warnings if you are satisfied, although you can probably restructure the code also (make the array size a
#define
for example).I don't understand
identify switched parameters
in your side note, you need to put the params in the same order as they are in the format string. -
answered 2022-05-02 17:09
chqrlie
The warning is caused by passing the same expression to
snprintf
for the first argument and the argument tosizeof
for the second. It is produced when the same pointer is used this way.Contrary to what you posted,
data
is a pointer, not an array in the offending code.This warning is a life saver, but the wording is catastrophic. It is not produced if
data
is an array, yet the text would still seem to apply:argument to 'sizeof' in 'int snprintf(char*, size_t, const char*, ...)' call is the same expression as the destination; did you mean to provide an explicit length? [-Wsizeof-pointer-memaccess]
Passing an explicit length is indeed less consistent than using
sizeof(array)
, butsizeof(array)
is more risky because it is not obvious ifarray
is an actual array or a pointer at the call site. This warning addresses this issue for standard functions, but alas it does not seem possible to enable it for other functions.Here is the explanation from the gcc documentation:
-Wsizeof-pointer-memaccess
Warn for suspicious length parameters to certain string and memory built-in functions if the argument uses
sizeof
. This warning triggers for example formemset(ptr, 0, sizeof(ptr));
ifptr
is not an array, but a pointer, and suggests a possible fix, or aboutmemcpy(&foo, ptr, sizeof(&foo));
.-Wsizeof-pointer-memaccess
also warns about calls to bounded string copy functions likestrncat
orstrncpy
that specify as the bound asizeof
expression of the source array. For example, in the following function the call tostrncat
specifies the size of the source string as the bound. That is almost certainly a mistake and so the call is diagnosed.void make_file(const char *name) { char path[PATH_MAX]; strncpy (path, name, sizeof path - 1); strncat (path, ".text", sizeof ".text"); … }
The
-Wsizeof-pointer-memaccess
option is enabled by-Wall
.-Wsizeof-array-argument
Warn when the
sizeof
operator is applied to a parameter that is declared as an array in a function definition. This warning is enabled by default for C and C++ programs.To allow the compiler to type check arguments to the
printf
andscanf
families of functions, you should pass-Wall -Wextra -Werror
for gcc and-Weverything -Werror
for clang.
do you know?
how many words do you know