нестатическое объявление после статического объявления

Рассмотрим эти примеры:

static int a;
extern int a; //OK -- what linkage does the a have now?

static int a;
int a; //ERROR

extern int a;
static int a; //ERROR

int a;
static int a; //ERROR

extern int a;
int a; //OK as expected

int a;
extern int a; //OK as expected

Почему в первом примере все было в порядке, а во втором нет?

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

Спасибо

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

РЕДАКТИРОВАТЬ: я пытался скомпилировать с помощью gcc 4.5.2 -Wall -pedantic --std=c99

Подробнее: http://c-faq.com/decl/static.jd.html Вы видите, что 1-й пример тоже работает, а 2-й — нет. Однако я не понимаю, чем они так отличаются.


person mindless    schedule 30.08.2011    source источник
comment
Можете ли вы рассказать больше о ваших вопросах? потому что в самом первом уходе вы прокомментировали OK, но это приводит к ошибке, говорящей о том, что статическое объявление «a» следует за нестатическим объявлением   -  person    schedule 30.08.2011


Ответы (2)


Ответ на ваш первый вопрос можно найти в §6.2.2 стандарта C:

4 Для идентификатора, объявленного с помощью спецификатора класса хранения extern в области, в которой видно предыдущее объявление этого идентификатора, если предыдущее объявление указывает внутреннюю или внешнюю связь, связь идентификатора в более позднем объявлении такая же, как и в предыдущем объявлении. связь, указанная в предыдущем заявлении. Если предыдущее объявление не видно или если предыдущее объявление не указывает на связь, то идентификатор имеет внешнюю связь.

Таким образом, связь a является внутренней.

Для вашего второго вопроса уместно второе предложение следующего абзаца:

5 Если в объявлении идентификатора функции отсутствует спецификатор класса памяти, ее связь определяется точно так же, как если бы она была объявлена ​​со спецификатором класса памяти extern. Если объявление идентификатора объекта имеет область действия файла и не содержит спецификатора класса хранения, его связь является внешней.

Поскольку a является объектом, а не функцией, объявление int a; без спецификатора класса хранения дает a внешнюю связь. В том же разделе говорится следующее:

7 Если в единице перевода один и тот же идентификатор появляется как с внутренней, так и с внешней связью, поведение не определено.

Поскольку во втором примере a появляется как с внутренней, так и с внешней связью, этот абзац срабатывает. Одним (особенно полезным) проявлением неопределенного поведения является ошибка, которую выдает ваш компилятор.

Все ваши примеры можно понять по этим правилам:

  1. int a; всегда объявляет a с внешней связью;
  2. static int a; всегда объявляет a с внутренней связью;
  3. extern int a; объявляет a с уже имеющейся связью или внешней связью, если ее не было;
  4. Два объявления a в одной и той же области с разными связями приводят к неопределенному поведению.
person caf    schedule 30.08.2011

У меня такая же ошибка, когда я забываю "{" вместо ";" в конце декларации.

Пример:

extern void *HASHMP_get(struct HASHMP_wf_s *hmwf_ptr, Uint8 *key);
extern void *HASHMP_remove(struct HASHMP_wf_s *hmwf_ptr, Uint8 *key) {
extern Uint16 HASHMP_clear(struct HASHMP_wf_s *hmwf_ptr);
person Alphan Karacaer    schedule 27.06.2019