c - Как инициализировать постоянную структуру - PullRequest
0 голосов
/ 24 февраля 2020

Я бы не хотел, чтобы в моих файлах C были жестко запрограммированы постоянные значения, поэтому мне было интересно, если бы у меня был способ инициализировать структурную константу непосредственно в файле заголовка, чтобы использовать ее везде, где я включал файл заголовка? (в способе #define для констант с простыми типами)

Все ответы, которые я нашел до сих пор, были:

const int var = 5; /*in header*/ 

, который работает только в C ++ (не C)

Использование C файла для инициализации константы, а это не то, что я ищу

Лучший ответ на этот пост: Как использовать extern для обмена переменными между исходными файлами ?

, что кажется немного сложным ...

Заранее спасибо за ответы или помощь, которую вы можете принести мне! :)

РЕДАКТИРОВАТЬ: я добавляю больше деталей к моему вопросу.

Я хочу сохранить аппаратные параметры системы, которую я использую в структуре:

struct parameters_Component1 {
     int const1 = 5;
     double const2 = 7,847
}
struct parameters_Component2 {
     int const1 = 6;
     double const2 = 9,3343
}

или структура, эквивалентная

#define myConst 5;

Я хочу перегруппировать эти значения констант в файл заголовка, к которому я могу получить доступ и изменить, а не в моем C коде для организационной цели

1 Ответ

1 голос
/ 25 февраля 2020

Я бы хотел, чтобы в моих файлах C не было жестко закодированных значений констант, поэтому мне было интересно, если бы у меня был способ инициализировать структурную константу непосредственно в файле заголовка, чтобы использовать ее везде, где я включал файл заголовка ? (в способе #define для констант с простыми типами)

Сначала вам нужно получить более четкое представление о том, что вы имеете в виду, относительно семантики языка C. В терминологии C константы являются syntacti c конструкциями, которые представляют определенные c значения в исходном коде. У них нет собственного связанного хранилища, и они доступны только для встроенных типов. То, что вы хотите, не является «константой» в этом смысле, или, по крайней мере, C не обеспечивает структурные константы в этом смысле. Это не имеет ничего общего с классификатором типа const.

В этой общей области C предлагает несколько вещей:

  • структура инициализаторы , которые работают аналогично константам для инициализации объектов структурных типов;
  • объекты, имеющие неизменяемый (const) структурный тип; и
  • составные литералы типа структуры.

Инициализаторы

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

header1.h

struct my_struct { int x; int y; };
#define MY_STRUCT_INITIALIZER { .x = 0, .y = 0 }

code1. c

// ...
// This is initialization, not assignment:
struct my_struct s = MY_STRUCT_INITIALIZER;

Инициализатор не имеет хранилища

Не изменяемые объекты

Как и в C ++, любой тип данных может быть const -квалифицированным для создания типа для объектов, которые не могут быть изменены. Таким образом, такие объекты должны получать свое значение из инициализатора, или быть параметрами функции, или же должны быть объявлены таким образом, чтобы их инициализировали по умолчанию, поскольку они не изменяются, что означает, что нет другого способа определить их значения. В отличие от инициализатора, это добросовестных объектов с типами данных и связанным хранилищем, и они могут использоваться в любом выражении, совместимом с их типом. Точно так же идентификаторы, связанные с const объектами, должны удовлетворять правилам C для области действия и связи, как и другие идентификаторы. В частности, хотя может быть несколько объявлений любого объекта с внешней (или внутренней) связью, может быть только один определение каждого.

Внешние объекты

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

header2.h

struct my_struct { int x; int y; };

// a declaration:
extern const struct my_struct shared_struct;  // NOTE: explicit "extern" and no initializer

my_struct_stuff. c

#include "header2.h"

// a definition:
const struct my_struct shared_struct = { .x = 1, .y = 2 };

прочее. c

#include "header2.h"

// no definition of shared_struct here

// ...
int x = shared_struct.x;
int y = shared_struct.y;
// ...

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

Внутренние объекты

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

header3. h

struct my_struct { int x; int y; };
static const struct my_struct local_struct = { .x = 1, .y = 2 };

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

Составные литералы

C также имеют составные литералы структурных типов, которые аналогичны в некоторых отношениях для строковых литералов. Они представляют добросовестных объектов, с типами данных и хранилищем, и имеют лексическую форму, которая напрямую передает значения объектов. Составные литералы могут иметь const -квалифицированные типы, но они не являются const по умолчанию, и в общем случае допустимо модифицировать объект, соответствующий составному литералу, любым способом, разрешенным его типом. Кроме того, в отличие от строковых литералов, составные литералы не обязательно имеют длительность хранения stati c. Кроме того, каждый внешний вид составного литерала представляет отдельный объект.

Лексически составной литерал напоминает оператор приведения для типа структуры, объединения или массива, примененный к соответствующему инициализатору для объекта этого типа:

header4.h

struct my_struct { int x; int y; };

#define MY_STRUCT_LITERAL ((struct my_struct) { .x = 42, .y = 42 })
/* or:
#define MY_STRUCT_LITERAL ((const struct my_struct) { .x = 42, .y = 42 })
 */

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

В целом

Ваш главный доступные альтернативы представлены выше. Для меня неясно, какую ценность вы цените в лексическом порядке в заголовочном файле, или сколько вы цените, а не, скажем, в сопроводительном исходном файле, представляющем единицу перевода. Мне также неясно, какую относительную важность вы придаете минимизации требований к хранению этих данных, или же должны быть значимы идентификаторы объектов структур. И поскольку вы подняли C ++ для сравнения, я не должен упускать из виду тот факт, что составные литералы являются функцией C, которую C ++ не предоставляет. Это соображения, которые вы должны учитывать при выборе этих возможностей.

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

...