C - Дублирующий символ, если включить заголовок, но отлично работает, если включить в исходный файл - PullRequest
0 голосов
/ 30 апреля 2020

У меня есть заголовочный файл, который содержит массив int

primes.h

#ifndef P_H
#define P_H
#include <inttypes.h>

uint64_t primes[] = {
    7,
    11,
};
#endif

в lib.h файле: #include "primes.h"

lib.c включает в себя lib.h

в main.c файле: #include "lib.h"

Тогда это вызывает ошибку: duplicate symbol '_primes' in:

Но если я переместу #include "primes.h" в lib.c работает нормально. Почему включение include в source и header может иметь значение?

Ответы [ 2 ]

2 голосов
/ 30 апреля 2020

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

  • Если main.c и lib.c оба включают lib.h, тогда у них обоих есть отдельные копии lib.h, скомпилированные в.
  • Если lib.h включает primes.h, то у них обоих есть свои собственные отдельные копии primes.h, скомпилированные в.
  • Если primes.h имеет определенный массив, то у них обоих есть копия этого массива.
  • И если у них обоих есть что-то с одинаковыми именами, определенными в обоих файлах, вы получите дублирующую ошибку определения.

Лучший способ исправить это - иметь только 1 определение массива primes со всеми его значениями в исходном файле (например, lib.c), и вам нужно использовать extern ключевое слово в primes.h без значений, чтобы объявить, что один из ваших файлов содержит фактический массив (в этом случае вы можете не указывать размер). Обратите внимание, что использование ключевого слова extern является своего рода обещанием для компилятора, что существует некоторый файл, содержащий фактический массив, и поэтому вам все еще нужен фактический массив в исходном файле:

// primes.h
extern uint64_t primes[];

// lib.c
#include "primes.h"
uint64_t primes[] = {
    7,
    11,
};

// main.c
#include "primes.h"
2 голосов
/ 30 апреля 2020

Вы определяете переменную в h-файле. Это означает, что вы можете включить этот h-файл только в один модуль компиляции, то есть в один c -файл. Поэтому, когда вы включаете его в lib.h и в случае, если lib.h включается в несколько c -файлов, вы попадаете в беду, т.е. несколько блоков компиляции будут определять переменную массива primes. Это не сработает.

Правило: Не определяйте переменные в h-файлах. Всегда делайте это в c -файлах.

(примечание: возможны исключения, но это золотое правило - придерживайтесь его, если только у вас нет веской причины для помещения переменных в h-файлы)

См. Этот ответ, чтобы узнать, как -на описание: { ссылка }

...