глобальное определение структур в С++

была довольно подробная ветка (228684) о том, как глобально (используя extern struct) объявить структуру, которую можно увидеть более чем в 1 файле c++, но я не могу понять, как именно это сделать (было много обсуждений о том, сделай это, сделай это, может быть, сделай это, попробуй это и т. д.).

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

Вещи, в которых я не разбираюсь... Должен ли я определить структуру? Должен ли я определять структуру в файле заголовка и включать этот заголовок в каждый исходный файл С++? Нужен ли макрос #ifndef в заголовочном файле? Нужно ли объявлять структуру extern в заголовке?


person Community    schedule 25.11.2008    source источник


Ответы (4)


Он называется заголовочным файлом.

в вашем заголовочном файле (назовите его foo.h)

#ifndef FOO_H
#define FOO_H
class X {
};
#endif

Затем в любых файлах C, которые у вас есть

#include "foo.h"
X x;

Для С++ более распространено/предпочтительно использовать класс, но вы также можете использовать структуру. Ключевое слово extern обычно относится к переменным, а не к объявлениям классов/структур. Вы должны сделать глобальную переменную extern в заголовочном файле (затем объявить ее не-extern) в одном из ваших файлов .cpp.

person David Nehme    schedule 25.11.2008
comment
#ifndef, #define и #endif предназначены для защиты вас от довольно распространенного случая, когда вы случайно включаете один и тот же файл дважды (обычно через какой-то третий файл). - person Tom Leys; 25.11.2008
comment
Я немного написал код на C только для того, чтобы познакомиться с указателями и тому подобным, поэтому я могу с уверенностью сказать, что мое невежество в C++ абсолютно. Тем не менее, что меня всегда беспокоило, так это то, что компилятору было бы так сложно проверить, был ли файл уже включен, и в этом случае избежать его повторного включения? - person Juan Pablo Califano; 26.11.2008
comment
Компиляторы @JuanPabloCalifano пытаются это сделать. Вы слышали о #pragma once? См. stackoverflow.com/a/34884735, чтобы узнать о сложности. - person L. F.; 03.05.2019

Структуры не могут быть внешними или статическими. Если вы хотите, чтобы структура использовалась более чем в двух единицах перевода, поместите определение структуры в заголовок:

foo.hpp

struct foo {
    int a;
    int b;
};

Затем включите этот заголовочный файл во все исходные файлы, используя эту структуру. Наличие структуры/класса/объединения, определенных в нескольких исходных файлах, совершенно допустимо, если каждый из них определен одинаково. Вы можете поместить Include Guard вокруг определения foo, чтобы предотвратить двойное включение foo в компилируется тот же исходный файл. (Таким образом, наличие нескольких foo в одной и той же программе допустимо, но наличие нескольких foo в одном и том же источнике (примечание: означает единицу перевода) недопустимо.) См. 3.2 One Definition Rule в стандарте C++ или a Черновик.

Когда вы видите это:

extern struct foo { int a; int b; } b;

Не foo является внешним, а b (объект) является внешним! В нем говорится, что b не определено, а просто объявлено, так что вы можете ссылаться на него.

person Johannes Schaub - litb    schedule 25.11.2008

Если вам нужна глобальная переменная; единая структура, доступная из нескольких единиц компиляции (файлы C++):

/* foo.h */
#ifndef EXAMPLE_FOO_H
#define EXAMPLE_FOO_H

struct foo {
    int a;
    int b;
};

extern struct foo globalFoo;

#endif /* EXAMPLE_FOO_H */

--

/* foo.cpp */
#include "foo.h"

struct foo globalFoo = { 1, 2 };

--

/* bar1.cpp */
#include "foo.h"

int test1()
{
    int c = globalFoo.b; //c is 2
}

--

/* bar2.cpp */
#include "foo.h"

int test2()
{
    int x = globalFoo.a; //x is 1
}

Строка «struct {}» в foo.h сообщает компилятору, как выглядит struct foo. Строка «extern struct» объявляет конкретную структуру foo с именем «globalFoo» с внешней связью. (Можно объединить эти два объявления, см. Ответ @ litb.) Это означает, что пользователи globalFoo (bar1/test1 и bar2/test2) будут искать структуру в другом месте, у них не будет собственных отдельных копий.

foo.cpp — это особый случай, определяющий globalFoo. У любой переменной может быть только одно определение, и в этом случае foo.cpp имеет определение globalFoo. Когда bar1 и bar2 ищут globalFoo «извне», они находят globalFoo из foo.cpp. Имя будет относиться к одной и той же фактической структуре во всех трех файлах.

Если бы extern не было, то во всех трех файлах .cpp была бы строка «struct foo globalFoo;» (Помните, #include — это просто копирование/вставка). Это [попытка] создать три разные структуры с одинаковыми именами, что приведет к беспорядку.

Примечание. Строка «extern struct foo globalFoo;» избыточна в случае foo.cpp, но это не имеет значения.

person aib    schedule 25.11.2008
comment
Это C++, зачем использовать struct foo вместо foo? - person L. F.; 03.05.2019

Вот небольшой пример:

#ifndef __my_header__
#define __my_header__

class my_class
{

};

#endif

Класс my_class будет виден в любом файле, содержащем этот заголовок. Я думаю, что в вашем вопросе есть что-то еще, но я не совсем понимаю, что.

person Ben Collins    schedule 25.11.2008
comment
Вам следует избегать префикса __, так как он не соответствует стандартам. __ зарезервировано для внутреннего использования компилятора - person JaredPar; 25.11.2008
comment
бззз. Это только для идентификаторов в глобальном пространстве имен. Эти макросы не появляются в предварительно обработанных источниках и, таким образом, не загрязняют глобальное пространство имен. - person Ben Collins; 26.11.2008
comment
В глобальном пространстве имен может быть идентификатор с именем my_header, определенный компилятором. - person John Dibling; 26.11.2008
comment
@BenCollins Нет. Они предназначены не только для идентификаторов в глобальном пространстве имен. Их можно использовать как ключевое слово, специальный токен или что угодно. - person L. F.; 03.05.2019