func () vs func (void) в c99



void func()
На практике пустой параметр означает, что принимается любой аргумент.



void func(void) принимает никаких аргументов.



но в стандартном C99, я нахожу такие строки:




6.7.5.3 деклараторы функций (включая прототипы)

14 список идентификаторов объявляет только идентификаторы параметров функции. пустой список в деклараторе функции, который является частью определения этой функции указывает, что функция не имеет параметров. пустой список в деклараторе функции, который не является частью определения этой функции, указывает, что информация о количестве или типах параметров не предоставляется.




согласно стандарту, func() и func(void) - это то же самое?

605   4  

4 ответов:

TL; DR

в декларациях,

void func1();     // obsolescent
void func2(void);

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

на определения

void func1() { }     // obsolescent

и

void func2(void) { }
  • первый объявляет и определяет функцию func1, который не имеет параметров и нет прототипа

  • последний объявляет и определяет функцию func2с прототипом, который не имеет параметров.

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

то есть, учитывая определения выше

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
и вызовы являются незаконными в строго соответствующих программах, поскольку они явно неопределенное поведение в соответствии с 6.5.2.2p6.

кроме того, пустые скобки считаются устаревшей функцией:

использование деклараторов функций с пустыми скобками (не деклараторы типа параметров прототип-формат) является устаревшим особенность.

и

использование определений функций с отдельными списками идентификаторов параметров и деклараций (а не деклараторов типов параметров и идентификаторов прототипов) является устаревшей функцией.

есть 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 помечены как устаревшие.

функции 6.11.6 деклараторы:

использование деклараторов функций с пустыми скобками (не деклараторы типа параметров прототип-формат) является устаревшей функцией.

по состоянию на 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

    Ничего не найдено.