Я читаю Стандарт C N1570 и столкнулся с некоторым недоразумением относительно связи.Как указано в 6.2.2. Linkages of objects
:
5 Если объявление идентификатора для функции не имеет спецификатора класса хранения, его связь определяется точно так же, как если бы она была объявлена с помощью спецификатора класса хранения extern., Если объявление идентификатора для объекта имеет область файла и не имеет спецификатора класса хранения, его связь является внешней.
Так что я догадался, чтонет разницы между extern
и отсутствием спецификатора класса хранения в объявлении идентификаторов объектов с областью действия файла.
Давайте рассмотрим следующий пример:
test.h
:
#ifndef _TEST_H
#define _TEST_H
int a;
void increment();
#endif //_TEST_H
test.c
:
#include "test.h"
void increment(){
a += 2;
}
main.c
:
#include <stdio.h>
#include "test.h"
int main(int argc, char const *argv[])
{
increment();
printf("a = %d\n", a);
}
Поскольку объявлено, что a
имеет внешнюю связь (область файла, без спецификатора класса хранения)a = 2
печатается, как и ожидалось.
Поэтому я заменил объявление a
на спецификатор extern
и не ожидал никакой разницы (согласно приведенному выше 6.2.2#5
):
test.h
:
#ifndef _TEST_H
#define _TEST_H
extern int a; // <---- Note extern here
void increment();
#endif //_TEST_H
Но теперь компоновщик жалуется:
CMakeFiles/bin.dir/main.c.o: In function `main':
main.c:37: undefined reference to `a'
liblibtest.a(test.c.o): In function `increment':
test.c:4: undefined reference to `a'
test.c:4: undefined reference to `a'
collect2: error: ld returned 1 exit status
Как Стандарт объясняет это поведение?Поскольку идентификаторы имеют одинаковую связь в обоих случаях, я ожидал, что поведение компоновщика также будет одинаковым.