在AIX头文件编译期间,我面临着这个问题。
头文件(header1.h)具有以下结构:
http://169.254.169.254/latest/user-data
.c文件中现在包括header1.h
<powershell>
New-Item C:\Temp\test.txt -ItemType file
</powershell>
<persist>true</persist>
当我使用xlc编译器编译上述.c文件时,会引发错误:
header1.h”,行xxxx:1506-221(S)初始化程序必须是有效的常量表达式。
make:1254-004最后一条命令的错误代码为1。
停止。
答案 0 :(得分:0)
与您对sx1
的奇怪初始化无关(它是一个嵌套的结构,因此您需要一个嵌套的初始化程序)。
{{1,'a'},{1,'a'},{1,'a'}};
当使用变量(的地址)时,DEF的扩展仅在运行时可用。正如编译器告诉您的那样,您只能使用常量表达式,这意味着该值必须在编译时清除。就像上面的例子一样。
您可能正在寻找offsetof
宏,它会得出一个常量表达式。 constant expression不能包含变量。幸运的是,结构的定义不是变量。
下面的示例摆脱了第二个结构,因为它不必要地使问题复杂化。您可以将其重新添加为您的代码。
AFAIK您需要完全声明Struct才能使用它。这就是sx1
的声明是正确的原因。
struct MyStruct{
int a;
int c;
int b;
};
static struct MyStruct sx1 = {offsetof(struct MyStruct,b),'B','A'};
int main()
{
printf("%d %c",sx1.a,sx1.b);
}
您可能要检查typedef structs
答案 1 :(得分:0)
好吧,除了您要说的以外,您还有几个错误。首先,您正在DEF
宏中封闭(这非常危险,因为您将表达式隐藏在宏实例化下面,并且使错误对您不可见),将具有不同指针类型的地址相减(这是非法的) )例如,如果您将DEF
重新定义为您的第一个struct
使用,则为:
#define DEF(f) (&sx1.f - &sx1.aa)
然后您会在扩展以下内容时出错:
DEF(bb) -> (&sx1.bb - &sx1.aa)
其中bb
是char
,而a
是int
(您将int *
减去char *
)。展开DEF
宏后,这将导致编译问题,但是您不会看到产生编译器错误的实际扩展。
第二,初始化程序只能使用常量表达式,这意味着仅生成常量或常量表达式的静态表达式,并且&
运算符必须在链接时间多数时候进行解析(这使表达式不是常量一个,但是在编译之间可能会改变的东西),甚至在运行时也可以更改(假设第一个&
的操作数是一个堆栈自动变量,而第二个操作数是一个全局的固定变量,那么每次初始化时,常数值会有所不同,具体取决于堆栈在运行时的增长方式。您不能在常数表达式中使用&
运算符作为一般规则。
第三,如果您尝试模拟ANSI offsetof(structure_type, field)
宏的定义,则可以使用类似(请注意,此定义会导致一些可能依赖于体系结构的技巧,因此,便携式):
#define OFFSETOF(type, field) ((size_t)(char *)(&((type*)0)->field))
如以下代码所示:
#include <stdio.h>
struct my_data_struct {
int a;
char b;
double c;
char d[100];
int e;
};
#define OFFSET_OF(type, field) ((size_t)(char *)(&((type*)0)->field))
int main()
{
#define P(f) printf("OFFSET_OF(struct my_data_struct, %s) == %zu\n", #f, OFFSET_OF(struct my_data_struct, f))
P(a);
P(b);
P(c);
P(d);
P(e);
}
产生以下结果的
$ run pru
OFFSET_OF(struct my_data_struct, a) == 0
OFFSET_OF(struct my_data_struct, b) == 4
OFFSET_OF(struct my_data_struct, c) == 8
OFFSET_OF(struct my_data_struct, d) == 16
OFFSET_OF(struct my_data_struct, e) == 116
$ _
在我的系统上。
(type*)0
是将NULL
文字转换为(type*)
的地址
((type*)0)->field
是在其字段field
上取消引用的空指针(不用担心,因为我们实际上并没有取消引用该值,而只是引用了它)
&((type*)0)->field
是它的地址。
(char *)(&((type*)0)->field)
是将地址转换为(char *)
的地址(因此指针算术为字节大小)。还有
((size_t)(char *)(&((type*)0)->field)
是将地址转换为size_t
值。
当然,此计算的一部分(如果不是大部分)取决于体系结构,这就是当今标准在标准库(#include <stddef.h>
)中包含某种此类宏的原因。因此,请勿使用我的定义(以防万一您的系统中没有它),并在编译器/库文档中搜索一个offsetof
宏,该宏向您显示结构中字段的位置。
最后一件事...因为我使用了常量指针值(所有内容都来自常量0
)并且没有减去引用,因此它在需要常量表达式的初始化程序中可用。
#include <stdio.h>
struct my_data_struct {
int a;
char b;
double c;
char d[100];
int e;
};
#define OFFSET_OF(type, field) ((size_t)(char *)(&((type*)0)->field))
static size_t my_vector[] = {
OFFSET_OF(struct my_data_struct, a),
OFFSET_OF(struct my_data_struct, b),
OFFSET_OF(struct my_data_struct, c),
OFFSET_OF(struct my_data_struct, d),
OFFSET_OF(struct my_data_struct, e),
};
您可以很好地解释所有这些内容here