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

Поведение:

static void name();
void name() {
    /* This function is now static, even if in the declaration
     * there is no static keyword. Tested on GCC and VS. */
}

Что любопытно, обратное вызывает ошибку времени компиляции:

void name();
static void name() {
    /* Illegal */
}

Итак, является ли это стандартом, и могу ли я ожидать, что другие компиляторы будут вести себя так же? Спасибо!

6
Thomas Bonini 22 Дек 2009 в 05:20

2 ответа

Лучший ответ

Стандарт C ++:

7.1.1 / 6: «Имя, объявленное в области пространства имен без спецификатора класса-хранилища, имеет внешнюю связь, если только оно не имеет внутренней связи из-за предыдущего объявления» [или если оно не является константой].

В вашем первом случае name объявлен в области видимости пространства имен (в частности, в глобальном пространстве имен). Таким образом, первое объявление изменяет связь второго объявления.

Обратное запрещено, потому что:

7.1.1 / 7: «Связи, подразумеваемые последовательными декларациями для данного объекта, должны быть согласованы».

Итак, во втором примере первое объявление имеет внешнюю связь (по 7.1.1 / 6), а второе - внутреннюю (явно), и они не согласуются.

Вы также спрашиваете о C, и я полагаю, что это то же самое. Но у меня есть книга по C ++ прямо здесь, а вы так же способны просматривать черновик стандарта C в Интернете, как и я ;-)

12
Steve Jessop 22 Дек 2009 в 05:32
Я использую C ++, но добавил тег C, потому что решил, что он будет таким же и в C.
 – 
Thomas Bonini
22 Дек 2009 в 05:44

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

Итак, во втором случае отсутствие static в прототипе означало, что функция была определена как НЕ статическая, а затем, когда она была позже объявлена ​​как статическая, это было ошибкой.

Если вы не укажете тип возвращаемого значения в прототипе, то по умолчанию будет int, а затем вы снова получите ошибку с типом возвращаемого значения void. То же самое происходит с __crtapi и __stdcall и __declspec() (в компиляторе Microsoft C).

3
Jonathan Leffler 22 Дек 2009 в 06:14