int foo (int argc, ...) против int foo () против int foo (void) в C - PullRequest
5 голосов
/ 20 марта 2012

Итак, сегодня я понял (впервые по общему признанию), что int foo() фактически отличается от int foo(void) тем, что первый допускает любое количество входов, а второй допускает ноль .

int foo() просто игнорирует какие-либо данные? Если да, какой смысл разрешать эту форму функции? Если нет, как вы можете получить к ним доступ и чем это отличается от наличия списка переменных аргументов (например, что-то вроде int foo (int argc, ...))?

Ответы [ 4 ]

4 голосов
/ 20 марта 2012

Ключом к пониманию этого является понимание стека вызовов. Что происходит, когда вы вызываете функцию в C (со стандартным ABI x86 - другие платформы могут отличаться), так это то, что вызывающая сторона помещает все аргументы в обратном порядке в стек перед вызовом вызываемого. Затем вызываемый может прочитать столько аргументов, сколько захочет. Если вы используете foo (void), очевидно, вы не будете читать ни одного. Если вы используете foo (int), вы сможете прочитать одно слово в стек под вашим текущим кадром.

Использование foo () (без указания аргументов) означает, что компилятору не нужно проверять аргументы, которые вы передаете foo. Все идет; нет контракта Это может быть полезно, если foo имеет две разные реализации, которые принимают разные типы в качестве аргументов, и я хочу иметь возможность программно их отключать. (Это также иногда полезно при написании функций на ассемблере, где вы можете обрабатывать стек и аргументы самостоятельно.) Но помните, что компилятор не собирается выполнять какую-либо проверку типов для вас, поэтому вы должны быть очень осторожны.

Это отличается от foo (int, ...), так как в этом случае функция на самом деле имеет доступ ко всем аргументам (используя varargs). Нет никакой причины когда-либо определять функцию с помощью foo (), поскольку она в основном эквивалентна foo (void). foo () полезна только для объявлений .

1 голос
/ 20 марта 2012

Сначала возьмите int foo().Эта форма представляет собой объявление функции, которое не предоставляет прототип , то есть не указывает число и типы ее аргументов.Это архаичная форма объявления функций - это то, как функции были первоначально объявлены в пред-ANSI C. Такая функция, однако, имеет фиксированное число и тип аргументов - просто объявление не говориткомпилятор, что это такое, так что вы несете ответственность за правильное получение там, где вы вызываете функцию.Вы объявляете такую ​​функцию с такими аргументами:

int foo(a, b)
    int a;
    char *b;
{
    return a + strlen(b);
}

Эта форма объявления функции устарела.

int foo(void) - это современное объявление, которое предоставляет прототип;он объявляет функцию, которая не принимает аргументов.int foo(int argc, ...) также предоставляет прототип;он объявляет функцию, которая имеет один фиксированный целочисленный аргумент и список переменных аргументов.

0 голосов
/ 02 сентября 2015

Ну, в C ++ две формы эквивалентны, и они обе объявляют функцию, которая не принимает аргументов. Если вы попытаетесь вызвать функцию и передать аргумент, компиляция выдаст ошибку.

С другой стороны, C и Objective-C оба по-разному относятся к двум формам. В этих языках первая форма объявляет функцию, которая принимает неизвестное число аргументов, тогда как вторая форма объявляет функцию, которая вообще не принимает аргументов. Итак, в C действует следующий код:

int foo() {
  return 5;
}
int main() {
  return foo(1, 2, 3);
}

Компилятор не жалуется, и код работает нормально (компилятор C ++ выдаст ошибку в этом же коде).

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

0 голосов
/ 20 марта 2012

В стандартном соответствии C вы должны использовать int foo(void), если функция не принимает никаких параметров.

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

Что касается основного, единственные стандартные способы (чистый c) записать их - это либо int main(void), либо int main(int argc, char **argv) (или char *argv [] (то же самое).

...