func () vs func (void) в c99
void func()
На практике пустой параметр означает, что принимается любой аргумент.
void func(void) принимает никаких аргументов.
но в стандартном C99, я нахожу такие строки:
6.7.5.3 деклараторы функций (включая прототипы)
14 список идентификаторов объявляет только идентификаторы параметров функции. пустой список в деклараторе функции, который является частью определения этой функции указывает, что функция не имеет параметров. пустой список в деклараторе функции, который не является частью определения этой функции, указывает, что информация о количестве или типах параметров не предоставляется.
согласно стандарту, func() и func(void) - это то же самое?
4 ответов:
TL; DR
в декларациях,
void func1(); // obsolescent void func2(void);поведение совершенно другое. Первый объявляет функцию без какого - либо прототипа-и она может принимать любое количество аргументов! В то время как последний объявляет функцию с прототипом, которая не имеет параметров и не принимает аргументов.
на определения
void func1() { } // obsolescentи
void func2(void) { }
первый объявляет и определяет функцию
func1, который не имеет параметров и нет прототипапоследний объявляет и определяет функцию
func2с прототипом, который не имеет параметров.эти два ведут себя отчетливо в том, что тогда как компилятор C должны печатаем диагностическое сообщение при вызове прототип функцию с неверным числом аргументов, она не нужно сделайте это при вызове функции без прототип.
то есть, учитывая определения выше
и вызовы являются незаконными в строго соответствующих программах, поскольку они явно неопределенное поведение в соответствии с 6.5.2.2p6.func1(1, 2, 3); // need not produce a diagnostic message func2(1, 2, 3); // must always produce a diagnostic message // as it is a constraint violationкроме того, пустые скобки считаются устаревшей функцией:
использование деклараторов функций с пустыми скобками (не деклараторы типа параметров прототип-формат) является устаревшим особенность.
и
использование определений функций с отдельными списками идентификаторов параметров и деклараций (а не деклараторов типов параметров и идентификаторов прототипов) является устаревшей функцией.
есть 2 связанных, но различных понятия: параметры и аргументы.
аргументы-это значения, переданные в функцию.
параметры-это имена / переменные внутри функции, которые устанавливаются в значения аргументов при вводе функции
в следующем фрагменте:
int foo(int n, char c) { ... } ... foo(42, ch);
nиcпараметры.42иchаргументы.цитируемый отрывок касается только параметров функции, но ничего не упоминает о прототипе или аргументах функция.
The декларация
void func1()означает, что функцияfunc1можно назвать любое число аргументы, т. е. информация о количестве аргументов не указана (как отдельное объявление, C99 указывает это как " функция без спецификации параметров), тогда как объявлениеvoid func2(void)означает, что функцияfunc2не принимаются аргументы на всех.цитата в вашем вопросе означает, что в течение определение функции,
void func1()иvoid func2(void)оба сигнализируют им, что нет параметры, т. е. имена переменных, которые установлены в значения аргументов при вводе функции. Элементvoid func() {}контрастирует сvoid func();первый заявляет, чтоfuncдействительно не принимает параметров, тогда как последний является объявлением для функцииfuncдля чего ни параметры , ни их типы указаны (объявление без прототипа).однако они все же отличаются определением-Мудрым в этом
определение
void func1() {}не объявляет прототип, тогда какvoid func2(void) {}, потому что()не является списком типов параметров, тогда как(void)- это список типов параметров (6.7.5.3.10):частный случай неназванного параметр типа void как единственный элемент в списке указывает, что функция не имеет параметров.
и далее 6.9.1.7
если Декларатор содержит список типов параметров, то list также определяет типы всех параметров; такой Декларатор также служит прототипом функции для последующих вызовов той же функции в той же единице перевода. Если Декларатор содержит список идентификаторов, типы параметров должны быть объявлены в следующем списке объявлений. В любом случае тип каждого параметра корректируется, как описано в пункте 6.7.5.3 для списка типов параметров; результирующим типом должен быть тип объекта.
Декларатор определения функции для
func1тут не содержат список типов параметров, и, следовательно, функция не имеет прототипа.
void func1() { ... }еще может вызывается с любым количеством аргументов, в то время как это ошибка времени компиляции для вызоваvoid func2(void) { ... }С любыми аргументами (6.5.2.2):если выражение, обозначающее вызываемую функцию, имеет тип , что включает в себя прототип, количество аргументов должно совпадать с количеством параметров. Каждый аргумент должен иметь такой тип, чтобы его значение могло быть присвоено объекту с неполной версией типа его соответствующего параметр.
(выделено мной)
это ограничения, который согласно стандарту говорит, что соответствующая реализация должны выведите хотя бы одно диагностическое сообщение об этой проблеме. Но так как
func1не имеет прототипа, соответствующая реализация не требуется для производства какой-либо диагностики.
однако, если количество аргументов не соответствует равное количество параметров, то поведение не определено6.5.2.2p6:
если выражение, обозначающее вызываемую функцию, имеет тип, который делает не имеется прототип, [...]если число аргументов не равно числу параметров, поведение не определено.
таким образом, теоретически соответствующий компилятор C99 также может ошибаться или диагностировать предупреждение в этом случай. рассказчик при условии, чтолязг может диагностировать это; однако мой GCC, похоже, не делает этого (и это также может потребоваться для того, чтобы он был совместим с каким-то старым неясным кодом):
void test() { } void test2(void) { } int main(void) { test(1, 2); test2(1, 2); }когда вышеуказанная программа компилируется с
gcc -std=c99 test.c -Wall -Werrorвывод:test.c: In function ‘main’: test.c:7:5: error: too many arguments to function ‘test2’ test2(1, 2); ^~~~~ test.c:3:6: note: declared here void test2(void) { } ^~~~~то есть аргументы вообще не проверяются по параметрам функции, объявление которой в определении не является прототипом (
test), тогда как ССЗ считает это-ошибка времени компиляции, чтобы указать аргументы к прототип функции (test2); любая соответствующая реализация должны диагностировать это, как это нарушение ограничений.
значительная часть цитаты выделена жирным шрифтом ниже:
6.7.5.3 деклараторы функций (включая прототипы) 14 список идентификаторов объявляет только идентификаторы параметров функции. Пустой список в деклараторе функций, который является часть определения этой функции указывает, что функция не имеет параметров. Пустой список в деклараторе функций, который является не является частью определения этой функции указывает, что сведения о количестве или типах параметров не предоставляются.
Так, если список параметров пуст для функции с ее телом, они одинаковы. Но это всего лишь объявление функции.
void function1(); // No information about arguments void function2(void); // Function with zero arguments void function3() { // Zero arguments } void function4(void) { // Zero arguments }
согласно стандарту, func () и func(void) - это одно и то же?
нет.
func(void)говорит, что функция принимает нет аргументы вообще; тогда какfunc()говорит, что функция принимает неопределенное количество аргументов. Оба действительны, ноfunc()стиль устарел и не должен использоваться.это побочный эффект от pre-C. стандарт С99 помечены как устаревшие.
использование деклараторов функций с пустыми скобками (не деклараторы типа параметров прототип-формат) является устаревшей функцией.
по состоянию на C11, он по-прежнему остается устаревшим и не был удален из стандарта.
пустой список параметров внутри определения функции означает, что он не включает прототип и не имеет никаких параметров.
C11 §6.9.1 / 7 определения функции (акцент в текущих кавычках-мой)
Декларатор в определении функции указывает имя определяется функция и идентификаторы ее параметров. если Декларатор содержит тип параметра list в списке также указывается типы всех параметров; такой Декларатор также служит в качестве прототип функции для последующих вызовов той же функции в том же единица перевода.
вопрос спрашивает:
согласно стандарту,
func()иfunc(void)- это то же самое?нет. Существенная разница между
void func()иvoid func(void)ложь в их призывах.C11 §6.5.2.2 / 2 ):
если выражение, обозначающее вызываемую функцию, имеет тип, который включает в себя прототип количество аргументов согласен с количество параметров. Каждый аргумент должен иметь такой тип, что его значение может быть присвоено объекту с неполной версией тип соответствующего параметра.
обратите внимание, что параметры arguments аргументы. Этот функция может не содержать параметров, но может иметь несколько аргументов.
поскольку функция, определенная с пустыми параметрами, не вводит прототип, она не проверяется на ее вызовы, поэтому теоретически она может поставляться с все количество аргументов.
однако, технически это неопределенное поведение называть такую функцию хотя бы один аргумент (см. Антти Хаапай-х комментарии).
C11 §6.5.2.2/6 ):
если количество аргументов не равно количеству параметров, поведение не определено.
следовательно, разница незначительная:
- когда функция определяется с
void, он не будет компилироваться, когда количество аргументов не совпадает с параметрами (вместе с их типами), из-за нарушения константы (§6.5.2.2/2). Такие ситуация требует диагностического сообщения от соответствующего компилятора.- если он определен с пустыми параметрами, то это мая или не может compile (нет требования для диагностического сообщения от соответствующего компилятора), однако это UB to вызов такая функция.
пример:
#include <stdio.h> void func1(void) { puts("foo"); } void func2() { puts("foo"); } int main(void) { func1(1, 2); // constraint violation, it shouldn't compile func2(3, 4); // may or may not compile, UB when called return 0; }отметим, что оптимизирующий компилятор может отрезать аргументы в таком случае. Например, вот как это делается Clang компилирует приведенный выше код (исключая
func1призыв) с-01на x86-64 в соответствии с соглашениями о вызовах SysV ABI:main: # @main push rax ; align stack to the 16-byte boundary call func2 ; call func2 (no arguments given) xor eax, eax ; set zero as return value pop rcx ; restore previous stack position (RSP) ret
Comments