Должны ли заголовки в квадратных скобках всегда стоять над цитируемыми заголовками для C++?

При компиляции исходного файла C++, если у вас есть несколько заголовков, состоящих из заключенных в скобки и цитируемых заголовков, всегда ли заголовки в квадратных скобках должны быть указаны первыми?

Я поместил заголовок в кавычки перед заголовком в квадратных скобках, и это начало давать мне ошибки компилятора переопределения.

Заголовочный файл (utilities.h):

#ifndef _UTILITIES_H
#define _UTILITIES_H

#include <vector>
double calcNorm(std::vector <double> array);   //template?

#endif

Исходный файл (utilities.cpp)

#include <math.h>
#include <vector>
#include "utilities.h"

double calcNorm(std::vector <double> array)   //template?
{
   int n;
   double norm = 0;

   n = array.size();
   for (int i = 0; i < n; i++)
   {
      norm += array[i]*array[i];
   }

   norm = sqrt(norm);

   return norm;
}

Раньше в исходном файле у меня был #include "utilities.h" над заголовками в квадратных скобках, и я получал следующую ошибку компилятора:

g++ -g -Wall -c utilities.cpp
utilities.cpp: In function ‘double calcNorm(std::vector<double>)’:
utilities.cpp:5:8: error: redefinition of ‘double calcNorm(std::vector<double>)’
 double calcNorm(std::vector <double> array)   //template?
        ^
utilities.h:3:8: note: ‘double calcNorm(std::vector<double>)’ previously defined here
makefile:12: recipe for target 'utilities.o' failed

Короткий ответ - нет'. Длинный ответ - MCVE, пожалуйста.

SergeyA 26.10.2018 21:57

Если вы не делаете ничего глупого и правильно включаете свои зависимости в каждый заголовок, то порядок включения не имеет значения. Но чтобы ответить на этот вопрос, в чем именно заключается ошибка и как выглядит файл заголовка? Я подозреваю, что вы using namespace std;что плохо вызываете конфликт имен, но вы должны показать код, чтобы быть уверенным

alter igel 26.10.2018 21:59

Чтобы быть ясным, MVCE относится к Минимальный, полный, проверяемый пример, который поможет сделать ваш вопрос доступным для ответа и который имеет то преимущество, что, вероятно, найдет ошибку за вас. Пожалуйста, редактировать ваш вопрос, чтобы включить его.

alter igel 26.10.2018 22:02

Мое практическое правило - сначала стандартные заголовки, затем заголовки библиотек, а затем мои собственные заголовки. Это упрощает поиск ошибок в моих заголовках. Однако это не обязательно.

NathanOliver 26.10.2018 22:03

@NathanOliver всегда всегда наоборот!

SergeyA 26.10.2018 22:04

Похоже, что в одном из цитируемых вами заголовков есть что-то плохое.

Galik 26.10.2018 22:06

Извините. Я только что обновил OP файлами, вызывающими эту ошибку.

24n8 26.10.2018 22:06
_UTILITIES_H - не самое уникальное имя. Также IIRC это может вызвать неопределенное поведение, потому что оно начинается с _, за которым следует заглавная буква (вряд ли проблема в реальной жизни).
Galik 26.10.2018 22:08

"#ifndef _UTILITIES_H" - Плохое название для защиты жатки. Любое имя, начинающееся с подчеркивания и сопровождаемое заглавной буквой, - это зарезервировано для реализации, и вам не разрешается его использовать. Также; это вряд ли будет уникальным. См. stackoverflow.com/questions/49688518/…

Jesper Juhl 26.10.2018 22:10

Я поменял для этого защиту включения и получил следующие ошибки: g++ -g -Wall -c utilities.cpp utilities.cpp: In function ‘double calcNorm(std::vector<double>)’: utilities.cpp:5:8: error: redefinition of ‘double calcNorm(std::vector<double>)’ double calcNorm(std::vector <double> array) //template? ^ utilities.h:3:8: note: ‘double calcNorm(std::vector<double>)’ previously defined here #pragma once ^ makefile:12: recipe for target 'utilities.o' failed make: *** [utilities.o] Error 1

24n8 26.10.2018 22:11

Я почти уверен, что это не полный MCVE. Порядок включения или плохое имя для защиты включения не может привести к ошибке, как сообщается.

SergeyA 26.10.2018 22:13

@NathanOliver Я использую противоположное соглашение: сначала собственные заголовки. Как ни странно, мои рассуждения точно такие же, как и ваши.

eerorika 26.10.2018 22:13

И я также изменил имя защиты заголовка, и это тоже не устранило проблему.

24n8 26.10.2018 22:14

Хм. Я думаю, что нашел проблему. У меня был этот двоичный файл с именем utilities.h.gch (не знаю, откуда он) в каталоге. Я удалил его, и проблема с компилятором исчезла.

24n8 26.10.2018 22:16

@ user2079303 и SergeyA. Думаю, я не должен был быть таким общим. В файле реализации для файла заголовка я делаю обратное тому, что я сказал, чтобы найти, есть ли в файле заголовка недостающие зависимости. В моем основном файле я делаю это так, как я сказал, поэтому мне не нужно беспокоиться о том, что мои включения заставят меня думать, что в стандартных включаемых файлах есть ошибка.

NathanOliver 26.10.2018 22:16

@SergeyA Полностью согласен. Я помещаю свой заголовок включает первый (если я не использую среду PCH, где, очевидно, сначала идет PCH, но я никогда не включаю это до конца проекта), затем заголовки библиотеки. Это гарантирует, что вы не создадите .h, который неявно зависит от других заголовков, извлеченных из включающего файла .cpp.

WhozCraig 26.10.2018 22:17

@NathanOliver я предпочитаю: сначала мои собственные заголовки, затем заголовки библиотеки, затем стандартные заголовки. Это гарантирует, что мои собственные файлы заголовков являются самодостаточными и не зависят от транзитивных включений.

Jesper Juhl 26.10.2018 22:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
17
87
4

Ответы 4

«заголовки в квадратных скобках всегда должны быть перечислены первыми» - Нет.

Это не имеет ничего общего с порядком включений, а все связано с правилами поиска включений. Оператор include, такой как #include "foo.h", заставит препроцессор сначала просмотреть текущий каталог исходного файла, тогда, независимо от того, какие пути включения вы указали (и пути по умолчанию). Оператор include, такой как #include <foo.h>, будет делать то же самое, за исключением того, что он пропускает начальный шаг «просмотр текущего каталога».

Нет. Единственная разница между заголовками, заключенными в угловые скобки, и заголовками, заключенными в кавычки, заключается в том, где их будет искать система. (Обратите внимание, что стандартные заголовки могут вообще не существовать как отдельные файлы; это деталь реализации, о которой вам не нужно беспокоиться.)

When compiling a C++ source file, if you have multiple headers consisting of bracketed and quoted headers, do the bracketed headers have to always be listed first?

Нет.

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

Технически заголовок может быть написан таким образом, чтобы перед ним были включены другие заголовки, но в целом это неприятный запах кода и чаще всего ошибка.


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

Hmmm. I think I found the issue. I had this binary file called utilities.h.gch (not sure where it came from) in the directory. I removed it and the compiler issue went away.

Ах. gch - это расширение файла, используемое предварительно скомпилированными заголовками, и это объясняет, почему вашего примера было недостаточно для воспроизведения вашей проблемы. Дополнительные сведения о том, как ведут себя предварительно скомпилированные заголовки, см. В руководстве к вашему компилятору.

Краткий ответ: Нет.

Длинный ответ: Директива #include практически буквально вставляет содержимое этого файла в исходный код. Заголовок должен быть включен до того, как будут использованы какие-либо его функции. Период. Если вы включите iostream в конце, но не используете этот заголовок, проблем не будет.

Другие вопросы по теме