Несколько включений одного и того же заголовочного файла в проекте: C против C ++ - PullRequest
1 голос
/ 29 октября 2019

Здесь у меня есть пример проекта с двумя исходными файлами и файлом заголовка, следующим образом:

main.c:

#include<stdio.h>                                                               
#include "personal.h"                                                           
int main(){                                                                     
    i = 5;                                                                        
    printf("Value is %d\n",i);                                                    
    return 0;                                                                     
 }

sub.c:

#include "personal.h"                                                           
// do nothing

и, наконец, personal.h:

#pragma once                                                                    
int i; 

Каждый из .c-файлов включает в себя personal.h, который "охраняется". Я компилирую с gcc, все идет хорошо:

>gcc sub.c main.c -o out
>./out 
Value is 5

Но с g ++ это происходит:

>g++ sub.c main.c -o out
/tmp/cctYwVnO.o:(.bss+0x0): multiple definition of `i'
/tmp/ccPElZ27.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status

Есть ли что-нибудь принципиально различное между C ++ и C с точки зрения того, как связаны файлы, препроцессорная активность и т. д.? Я попробовал то же самое с другими компиляторами, такими как clang, и то же самое происходит. Возможно, мне здесь не хватает чего-то глупого.

Ответы [ 2 ]

7 голосов
/ 29 октября 2019

В C

int i;

является предварительным определением. В силу включения у вас есть предварительное определение для i в двух единицах компиляции. Стандарт C позволяет иметь предварительные определения в нескольких единицах компиляции, но не требует, чтобы реализация принимала это. Пользовательское поведение для компиляторов Unix C состоит в том, чтобы разрешить это, но у gcc есть опция (-fno-common), чтобы предотвратить это и генерировать ошибку во время компоновки (так что вы можете проверить код для компиляторов, как я думаю, Microsoft, который делаетне разрешать это или для платформ, для которых это позволяет лучший код - я не знаю ни одного, но это обоснование, приведенное в документации GCC).

IIRC, C ++ не имеет такого разрешения.

Обратите внимание, чтоВы, вероятно, хотите объявление, а не определение в заголовках. Таким образом, для i выше должно быть

extern int i;

в заголовке и один

int i;

в глобальной области видимости в одном .c файле.

1 голос
/ 29 октября 2019

sub.c будет включать personal.h и создаст переменную i в глобальной области видимости. Точно так же main.c будет также включать personal.h и создавать переменную i в глобальной области видимости. В конце концов, когда вы ссылаетесь, в глобальной области видимости есть два определения i и, следовательно, ошибка.

...