Связь в C: соответствует ли GCC спецификации C99 или я не понимаю спецификацию?

Я пытаюсь понять точное поведение спецификаторов класса хранения в C99, и некоторые действия GCC, кажется, не соответствуют спецификации, если только я не понимаю спецификацию неправильно. Из 6.2.2 (2):

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

Однако я протестировал GCC (powerpc-apple-darwin9-gcc-4.2.1) со следующей программой:

#include <stdio.h>
static int f() {
    static int x = 0;
    return x++;
}
static int g() {
    static int x = 0;
    return x++;
}
int main(int argc, char *argv[]) {
    printf("g() = %i\n", g());
    printf("g() = %i\n", g());
    printf("f() = %i\n", f());
    printf("f() = %i\n", f());
    return 0;
}

Скомпилированный с -std=c99, он печатает следующее:

g() = 0
g() = 1
f() = 0
f() = 1

Если я правильно понимаю спецификацию, она должна печатать:

g() = 0
g() = 1
f() = 2
f() = 3

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


person Dietrich Epp    schedule 29.01.2010    source источник


Ответы (2)


Следующий параграф, 6.2.2/3, важен:

Если объявление идентификатора области файла для объекта или функции содержит спецификатор класса хранения static, идентификатор имеет внутреннюю связь.

(обратите внимание на выделенный идентификатор области файла).

Ваши статические переменные x не имеют файловой области, они имеют блочную область.

person James McNellis    schedule 29.01.2010
comment
Другими словами, каждый x является локальным для функции, которая его объявляет. - person Richard Pennington; 29.01.2010
comment
Спасибо. В спецификации легко пропустить слова. - person Dietrich Epp; 29.01.2010
comment
@Дитрих: Это так. На самом деле, это так просто, что я пропустил более важную и важную часть, которая была опубликована в качестве ответа. - person James McNellis; 29.01.2010

В 6.2.2 (6) сказано:

Следующие идентификаторы не имеют связи: [...] идентификатор области блока для объекта, объявленного без спецификатора класса хранения extern.

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

person sth    schedule 29.01.2010