Hoo*_*ood 0 c struct global header constants
我想避免在我的 C 文件中硬编码常量值,所以我想知道是否有办法直接在头文件中初始化结构常量,以便在我包含头文件的任何地方使用它?(以 #define 适用于简单类型常量的方式)
到目前为止我找到的所有答案都是:
const int var = 5; /*in header*/
Run Code Online (Sandbox Code Playgroud)
只适用于 C++(不适用于 C)
使用 C 文件来初始化常量,这不是我要找的
这篇文章的最佳答案:如何使用 extern 在源文件之间共享变量?
这似乎有点复杂......
预先感谢您能给我带来的答案或帮助!:)
编辑:我正在为我的问题添加更多详细信息。
我想存储我在结构中使用的系统的硬件参数:
struct parameters_Component1 {
int const1 = 5;
double const2 = 7,847
}
struct parameters_Component2 {
int const1 = 6;
double const2 = 9,3343
}
Run Code Online (Sandbox Code Playgroud)
或等效于的结构
#define myConst 5;
Run Code Online (Sandbox Code Playgroud)
我希望将这些常量值重新分组到一个我可以访问和修改的头文件中,而不是出于组织目的而放在我的 C 代码中
我想避免在我的 C 文件中硬编码常量值,所以我想知道是否有办法直接在头文件中初始化结构常量,以便在我包含头文件的任何地方使用它?(以 #define 适用于简单类型常量的方式)
您首先需要更清楚地了解相对于 C 语言语义的含义。在 C 术语中,常量是表示源代码中特定值的语法结构。它们没有自己的关联存储,并且仅适用于内置类型。你想要的不是这个意义上的“常量”,或者至少,C 没有提供这个意义上的结构常量。这与类型限定符无关const
。
C 在这个一般领域提供了一些东西:
const
;和顾名思义,初始化器可以在对象声明中使用来初始化声明的对象。然而,它们本身不是值,因此不能在声明后将它们分配给对象,也不能在需要表达式的情况下使用它们。您可以定义一个扩展为初始值设定项的宏,有时会这样做。例子
header1.h
struct my_struct { int x; int y; };
#define MY_STRUCT_INITIALIZER { .x = 0, .y = 0 }
Run Code Online (Sandbox Code Playgroud)
代码1.c
// ...
// This is initialization, not assignment:
struct my_struct s = MY_STRUCT_INITIALIZER;
Run Code Online (Sandbox Code Playgroud)
初始化器没有自己的存储空间。
与 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
Run Code Online (Sandbox Code Playgroud)
my_struct_stuff.c
#include "header2.h"
// a definition:
const struct my_struct shared_struct = { .x = 1, .y = 2 };
Run Code Online (Sandbox Code Playgroud)
其他.c
#include "header2.h"
// no definition of shared_struct here
// ...
int x = shared_struct.x;
int y = shared_struct.y;
// ...
Run Code Online (Sandbox Code Playgroud)
这提供了一个不可修改的对象,可以在任意数量的翻译单元之间共享,但它不满足将所有内容都保留在标头中的标准。可以玩条件编译游戏,让定义按词法出现在标头中,但您仍然需要一个指定的源文件来提供定义。(细节留作练习。)
或者,如果在每个翻译单元中使用等效但不同的对象就足够了,那么您的标头可以定义一个不可修改的对象,其标识符具有内部链接。然后,包含标头的每个翻译单元都将拥有自己的独立对象副本:
header3.h
struct my_struct { int x; int y; };
static const struct my_struct local_struct = { .x = 1, .y = 2 };
Run Code Online (Sandbox Code Playgroud)
这满足了将所有内容保留在头文件中的标准,但即使不考虑存储使用的考虑,您也可能有理由希望为每个翻译单元提供相同的对象,但这并不能实现该目标。此外,您的编译器可能会针对包含标头但不访问local_struct
.
C 还具有结构类型的复合文字,它们在某些方面类似于字符串文字。它们代表真正的对象,具有数据类型和存储,并且具有直接传达对象值的词汇形式。复合文字可能具有const
- 限定类型,但默认情况下并非如此const
,并且一般来说,以其类型允许的任何方式修改与复合文字对应的对象是可以接受的。此外,与字符串文字不同,复合文字不一定具有静态存储持续时间。此外,复合文字的每次出现都代表一个单独的对象。
从词法上来说,复合文字类似于结构体、联合或数组类型的强制转换运算符,应用于该类型对象的相应初始值设定项:
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 })
*/
Run Code Online (Sandbox Code Playgroud)
扩展为复合文字的宏可以在标头中定义,如图所示,但重要的是要了解此类宏的每次出现都将对应于一个单独的对象。在某些情况下,编译器可能会优化保留任何实际存储,但复合文字并不是与整数或浮点常量相同意义上的“常量”。
上面列出了您的主要可用替代方案。我不清楚您对将值按词法出现在头文件中(而不是在表示翻译单元的随附专用源文件中)有何重视或有多大价值。我也不清楚您认为最小化这些数据的存储需求的相对重要性是什么,或者结构的对象标识是否需要很重要。由于您提出了 C++ 进行比较,我不应该忽视这样一个事实:复合文字是 C++ 不提供的 C 功能。这些是您在选择这些可能性时应该牢记的考虑因素。
或者您也可以考虑是否真的想将数据排列在实际的结构对象中。我之所以关注这一点,是因为这是您所问的问题,但是有一些基于宏的选项,可以让您以相当紧凑的形式在标题中列出数据,并使用类似函数的宏而不是结构访问语法来访问他们。