2013-12-19 4 views
2

Я знаю, что объявление функции (или указателя функции) без списка параметров (и без указания void в списке параметров) означает, что функция (или функция указатель) имеет неизвестное количество аргументов.Указатель функции «назначение из несовместимого типа указателя» только при использовании vararg ellipsis

Я написал несколько сценариев тестирования, чтобы проверить это поведение вне:

int my_func_1() { 
    return(0); 
} 
int my_func_2(int x) { 
    return(x); 
} 
int my_func_3(char x, ...) { 
    va_list va; 
    va_start(va, x); 
    return(va_arg(va, int)); 
} 


int (*fp)(); 

fp = my_func_1; 
printf("%d\n", fp()); 

fp = my_func_2; 
printf("%d\n", fp(33)); 

fp = my_func_3; 
printf("%d\n", fp(33, 44)); 

Что я составил на 64 битной машине под Linux как таковой:

gcc test.c -Wextra -pedantic -std=c1x -O3 -o test 

Выход правильно:

0 
33 
44 

Но я получаю это предупреждение: assignment from incompatible pointer type. Почему это предупреждение появляется только при использовании эллипса vararg?

Поскольку тип указателя считается неполным, его полный тип не должен составлять «назначение из несовместимого типа указателя». Более того, назначение полных типов работает без каких-либо предупреждений, если нет эллипса vararg.

Этот вопрос other задает почти то же самое. Ответы все в строке «это не работает», без четкой ссылки на стандарт о том, почему это не сработает.


  • Почему компилятор генерирует предупреждение?
  • Надежное ли это поведение (предупреждение в сторону)?
  • Является ли это специфическим компилятором поведения (прочитав другой вопрос, похоже, что mingw x86_64 не поддерживал его в 2011 году)?
  • Является ли это поведение конкретной платформой?
+0

Зачем беспокоиться об этом? Никакой разумный код C в этом столетии не использует бесцельные прототипы. * Ответы все в строке «это не работает» * - нет, принятый ответ говорит, что это неопределенное поведение. –

+0

Мне просто интересно; У меня есть достойное понимание внутренности C, и когда я вижу возможность испытать мое понимание/предположения и т. Д., Я иду на это. –

+2

Ваш вопрос выходит за рамки этого. например, вы спрашиваете, является ли поведение надежным ... ну, UB не является надежным. –

ответ

1

См 6.7.5.3 в C стандарт:

Кроме того, списки типа параметра, если присутствуют оба, согласовывают числа параметров, и при использовании многоточие терминатором; соответствующие параметры должны иметь совместимые типы. Если один тип имеет , список типов параметров и другой тип указывается функцией декларатором, который не является частью определения функции и содержит пустой список идентификаторов, список параметров не должен содержать терминатор с нулевым знаменем и тип каждого параметра должны быть совместимы с типом, который возникает в результате применения промо-акций по умолчанию .

Это говорит о том, что назначение функции varargs для fp имеет несовместимые типы.

Кроме того, как я отметил в своих комментариях выше, у программы есть неопределенное поведение, которое по определению ненадежно ... оно может работать в одной версии одной реализации на одной платформе, но не работать в других версиях, реализациях и платформах ... он может работать даже один день, но не следующий, или в одной части программы, но не другой.Прагматично, в некоторых реализациях вызывающие последовательности функций varargs и non-varargs различны, и ваша программа, вероятно, сбой при запуске в такой реализации.

+0

A-ha! Поэтому в спецификации четко указано, что «пустые списки» несовместимы с «терминаторами с многоточием». –

+0

@MihaiStancu Обратите внимание, что я добавил текст, чтобы сделать мой ответ более полным, так как вы его приняли. –

+0

Я попросил информацию о надежности и переносимости, потому что есть много расширений/функций компилятора, которые работали в одном компиляторе задолго до того, как они были добавлены в стандарт, в конечном итоге они получили поддержку от всех компиляторов, а спустя годы закончились в спецификации (гибкие поля массива, анонимные структуры/союзы, анонимные поля и т. д.). –