Snprintf ошибка. аргумент sizeof совпадает с аргументом назначения
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
ошибка: аргумент для вызова 'sizeof in' snprintf - это то же выражение, что и пункт назначения; Вы имели в виду предоставить ясную длину?
Примечание. Я использую флаги -Wall -Werror, которые преобразуют предупреждение в ошибку.
Здесь что-то похожее
В комментарии кто-то ответил на это
"Для буферов с фиксированной длиной я обычно использую strncpy (dest, src, sizeof (dest)); dest [sizeof (dest) -1] = '\ 0'; Это гарантирует завершение NULL и это всего лишь меньше хлопот, чем snprintf не говоря уже о том, что многие люди используют snprintf (dest, sizeof (dest), src) и вместо этого очень удивляются, когда их программы сбой произвольно".
Но это неправильно:
gcc 4.8 сказать
"error: аргумент для 'sizeof in' вызов strncpy - это то же выражение, что и пункт назначения, вы имели в виду предоставить явную длину? [-Werror = sizeof-pointer-memaccess]" /p >
в документации 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;
}
Дает следующую диагностику:
warning: аргумент "sizeof in" void memset (void *, int, size_t) - это то же выражение, что и пункт назначения; Вы имели в виду разыгрывать это? [-Wsizeof-указатель memaccess] memset (p1, 0, sizeof (p1));//ошибка ^
Хотя эти предупреждения не приведут к сбою компиляции, часто -Wall используется в сочетании с -Werror, и в результате новые предупреждения превращаются в новые ошибки.
Чтобы исправить, либо перепишите для использования memcpy, либо разыщите последний аргумент в нарушающем вызове memset. *
Ну, в их примере, очевидно, что код был неправильным, но в моем случае, с snprintf/strncpy, я не понимаю, почему, и я думаю, что это ложная ошибка positif gcc. Правильно?
спасибо за помощь
Ответы
Ответ 1
Массив распадается на указатель на первый элемент при передаче функции. Итак, что вы имеете в
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)
эквивалентны.
Читайте здесь: что такое разложение массива?
Ответ 2
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 $
Вот почему.
Ответ 3
В определении функции объявление параметра:
static inline void toto(char str[3])
не объявляет str
как массив (C не имеет параметров типа массива). Скорее, это точно эквивалентно:
static inline void toto(char *str)
3
игнорируется.
Итак, sizeof(str)
не имеет никакого отношения к числу символов, которые может содержать строка, это просто размер указателя char*
.
Это результат правила, в котором говорится, что параметр, объявленный с типом массива, "настроен" на тип указателя. Это отличается от правила, согласно которому выражения типа массива неявно преобразуются (или "распадаются" ) на указатели в большинстве контекстов. Два правила работают вместе, чтобы сделать код, который имеет дело с массивами, похоже, что он имеет дело с массивами напрямую, когда он действительно работает с указателями на элементы массивов.
Связь между C-массивами и указателями часто сбивает с толку. Я рекомендую прочитать раздел 6 comp.lang.c FAQ; он очень хорошо объясняет это.
Ответ 4
static inline void toto(char str[3])
определяет функцию, которая может принимать массив любого размера. 3
игнорируется, а str
рассматривается как указатель (try printf("%d\n", sizeof(str))
: на моей машине он печатает 8 для размера 64-разрядного указателя). В этом случае компилятор действительно прав.
Кланг дает полезное предупреждение здесь:
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");