C ++ void с префиксом вызова функции. например. `main () {void func ();}` - PullRequest
4 голосов
/ 04 августа 2011
void func() {assert(0);}
int main () {void func();}

Приведенный выше код не вызывает func () или, по крайней мере, не достигает утверждения.Не то чтобы мне действительно нужно было это знать, но мне просто интересно, что здесь происходит?

Ответы [ 4 ]

10 голосов
/ 04 августа 2011

Вы объявляете прототип для функции с именем func, которая ничего не возвращает и не принимает аргументов.Это (одно из) тонкое различие между вызовами функций и прототипами функций.Обратите внимание, что строка выше main, void func() {assert(0);}, не влияет на то, является ли это прототипом или вызовом.Вы можете удалить его, и код будет делать то же самое, то есть ничего.

Это также говорит о том, что вы можете повторно объявить прототипы функций.Вы могли бы даже иметь это:

int main() {
    void blah();
    void blah();
    void blah();
    void blah();
}

И код все равно будет делать то же, что и раньше - ничего.

Если вы пропустите void, он вызовет функцию.

Также обратите внимание, что в случае функции, которая принимает параметры, это:

int main() { func(4); }

не превратится в прототип, если вы добавили void до того, как это было сделано:

int main() { void func(4); }

это просто приведет к синтаксической ошибке.

5 голосов
/ 04 августа 2011

Как уже отмечали другие, линия

void func();

внутри main рассматривается как прототип функции, а не как вызов функции func. В C и C ++ вы можете объявить прототипы функций внутри функций, если хотите, хотя на практике это редко делается.

Тот факт, что это законно, вызывает у программистов всевозможные головные боли. Например, если вы переписали код как

(void) func();

Тогда это будет скомпилировано как вызов func, тип возвращаемого значения которого явно приведен к void, чтобы указать: «Меня не волнует это возвращаемое значение». Другими словами, этот набор скобок превращает объявление в оператор.

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

Object myObject();

Хотя

Object myObject(137);

создает объект и передает 137 в его конструктор, а

Object myObject;

создает объект без вызова конструктора.

Существует ужасный крайний случай языка, называемого "самым неприятным синтаксическим анализом", который возникает при попытке объявить объект при вызове его конструктора. Например, этот код является допустимым C ++, но это объявление функции, а не объявление переменной:

set<int> mySet(istream_iterator<int>(cin), istream_iterator<int>());

Проблема в том, что это может быть проанализировано как объявление функции, а не как создание объекта, который принимает два временных istream_iterator<int> s в качестве параметров. Чтобы это исправить, в C ++ вам нужно написать

set<int> mySet(istream_iterator<int>(cin), (istream_iterator<int>()));

Где, как и выше, лишние скобки принудительно устраняют неоднозначность оператора от прототипа функции до объявления.

Надеюсь, это поможет!

4 голосов
/ 04 августа 2011

Вы можете объявить функции, даже если это не нужно.Это то, что вы сделали, повторно объявили функцию.

0 голосов
/ 04 августа 2011

Вы объявляете локальную функцию void func() внутри main().Оператор void указывает компилятору, что это объявление, а не вызов функции.Итак, удалите void, ваша функция будет вызвана.

...