Почему нет ошибки дублирования определения, когда я определяю `const int` в файле заголовка?

#c #compilation #linker #extern

#c #Сборник #компоновщик #внешний

Вопрос:

Прошу прощения, если об этом спрашивали раньше. Я искал в Интернете и не нашел ответа.

Допустим, у меня есть файл Common.h , и A.cpp и B.cpp включить Common.h .

Если я хочу иметь глобальную const char * в Common единице перевода, я должен сделать это extern в Common.h и определить в Common.cpp . В противном случае, если я просто определяю const char * MSG = "Hello World"; в Common.h , я получаю duplicate symbol ошибку во время компиляции.

Однако, если я просто определяю глобальный const int в Common.h с помощью инструкции типа const int CONSTANT = 10; , тогда код компилируется без ошибки повторяющегося символа, и все работает нормально.

Я не понимаю, почему это так. Мне кажется, что единственное различие между двумя приведенными выше примерами заключается в типе, который, я думаю, не должен иметь значения. Почему я получаю ошибку дублирования символа для C-строк, но не целых чисел?

Предположим, main.cpp , A.h B.h A.cpp и B.cpp выглядят следующим образом:

 // A.h
#pragma once
void f();
  
 // A.cpp
#include "A.h"
#include "Common.h"

#include <iostream>

void f() {
    std::cout << MSG << std::endl;
}
  
 // B.h
#pragma once
void g();
  
 // B.cpp
#include "B.h"
#include "Common.h"

#include <iostream>

void g() {
    std::cout << CONSTANT << std::endl;
}
  
 // main.cpp
#include "A.h"
#include "B.h"

int main()
{
    f();
    g();
}
  

Теперь предположим, что мы выполняем компиляцию с помощью команды g main.cpp A.cpp B.cpp Common.cpp -std=c 14 .

Если мы сделаем Common.h и Common.cpp следующее, то компиляция завершится ошибкой duplicate symbol MSG :

 // Common.h
#pragma once
const char * MSG = "Hello World";
const int CONSTANT = 10; // defined in header file
  
 // Common.cpp
// empty
  

Однако это компилирует:

 // Common.h
#pragma once
extern const char * MSG;
const int CONSTANT = 10; // defined in header file
  
 // Common.cpp
#include "Common.h"
const char * MSG = "Hello World";
  

Мне интересно, зачем нам нужен extern и разделять определение и объявление для строки, но не для int.

Кто-то предложил сделать тип C-string as const char * const вместо const char * . Почему создание указателя const работает? Кроме того, в этом случае, в чем разница между этим решением и решением, которое я предоставил выше (где вместо этого мы создаем строку extern и разделяем определение / объявление)? Почему оба метода устраняют ошибку компиляции и в чем разница между этими методами?

Я также заметил, что если я превращаюсь const int в just int , то снова получаю duplicate symbol ошибку. Я чувствую, что причина этого связана с ответом на мои вопросы выше. Почему это так?

Комментарии:

1. Ничто так не описывает код, как хорошо написанный код.

2. const char *MSG означает вызываемую неконстантную переменную MSG . const является частью указанного типа .

3. пожалуйста, не помечайте несвязанные языки. C и C — разные языки с разными правилами. ваша программа, похоже, написана на C

4. @chux-ReinstateMonica Я предоставил код

5. @AnttiHaapala Концепции, о которых я спрашиваю, применимы как к C, так и к C

Ответ №1:

Это одно из различий C и C .

В C const переменная является неявной static , то есть видимой только для текущей единицы перевода. В C это неявно extern так заметно для всей программы (что также является значением по умолчанию для других неконстантных деклараций как в C, так и в C ).

Это объясняет ваше наблюдение.

Примечание: const char *p Объявление переменной не является const переменной. Это означает, что он указывает на переменную const (т. е. *p не может быть изменен), но p сам по себе не является const . Итак, поведение здесь другое. const char * const p было бы объявлением const.

Комментарии:

1. Это имеет смысл. Отвечает на все мои вопросы выше. Спасибо!