Заголовок / Включить охранники не работают? - PullRequest
5 голосов
/ 28 октября 2011

По какой-то причине я получаю несколько объявлений содержимого в моем заголовочном файле, хотя я использую средства защиты заголовков. Мой пример кода ниже:

main.c:

#include "thing.h"

int main(){
    printf("%d", increment());

    return 0;
}

thing.c:

#include "thing.h"

int increment(){
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

int something = 0;

int increment();

#endif

Когда я пытаюсь скомпилировать это, GCC говорит, что у меня есть несколько определений переменной что-то. ifndef должен убедиться, что этого не произойдет, поэтому я не понимаю, почему это так.

Ответы [ 6 ]

10 голосов
/ 28 октября 2011

Защитные щитки работают правильно и не являются источником проблемы.

В результате получается, что каждый модуль компиляции, включающий thing.h, получает свой собственный int something = 0, поэтому компоновщик жалуется на несколько определений.

Вот как это исправить:

thing.c:

#include "thing.h"

int something = 0;

int increment(){
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

extern int something;

int increment();

#endif

Таким образом, только thing.c будет иметь экземпляр something, а main.c будет ссылаться на него.

4 голосов
/ 28 октября 2011

Защита заголовка остановит сборку файла более одного раза в одном и том же модуле компиляции (файле). Вы включаете его в main.c и thing.c, поэтому он будет скомпилирован один раз в каждом, что приведет к объявлению переменной something один раз в каждом модуле или всего два раза.

3 голосов
/ 28 октября 2011

У вас есть одно определение в каждой единице перевода (одно в main.c и одно в thing.c).Защитники заголовка предотвращают включение заголовка более одного раза в одну единицу перевода.

Вам необходимо объявить something в файле заголовка и только определить в thing.c, как в функции:

thing.c:

#include "thing.h"

int something = 0;

int increment(void)
{
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

extern int something;

int increment(void);

#endif
1 голос
/ 28 октября 2011

старайтесь избегать определения переменных глобально.используйте функции, такие как increment (), чтобы изменить и прочитать его значение.таким образом, вы можете сохранить переменную статической в ​​файле thing.c и точно знать, что только функции из этого файла будут изменять значение.

1 голос
/ 28 октября 2011

Переменная something должна быть определена в файле .c, а не в заголовочном файле.

Только структуры, макросы и объявления типов для переменных и прототипов функций должно быть в заголовочных файлах. В вашем примере вы можете объявить тип something как extern int something в заголовочном файле. Но определение самой переменной должно быть в файле .c.

С тем, что вы сделали, будет определена переменная something в каждом .c файле, который включает thing.h, и вы получите сообщение об ошибке «что-то определено несколько раз», когда GCC пытается установить связь все вместе.

0 голосов
/ 28 октября 2011

, что ifndef охраняет, это один .h, включенный в .c более одного раза. Например,

вещь. ч

#ifndef
#define

int something = 0;
#endif

thing2.h

#include "thing.h"

main.c

#include "thing.h"
#include "thing2.h"
int main()
{
  printf("%d", something);
  return 0;
}

если я оставлю ifndef, то GCC будет жаловаться

 In file included from thing2.h:1:0,
             from main.c:2:
thing.h:3:5: error: redefinition of ‘something’
thing.h:3:5: note: previous definition of ‘something’ was here
...