我偶然发现了这个简单的程序
#include<stdio.h>
#include<stdlib.h>
char buffer[2];
struct globals {
int value;
char type;
long tup;
};
#define G (*(struct globals*)&buffer)
int main ()
{
G.value = 233;
G.type = '*';
G.tup = 1234123;
printf("\nValue = %d\n",G.value);
printf("\ntype = %c\n",G.type);
printf("\ntup = %ld\n",G.tup);
return 0;
}
它正在编译(使用gcc)并执行得很好,我得到以下输出:
Value = 233
type = *
tup = 1234123
我不确定#define G语句是如何工作的。 如何将G定义为struct globals类型的对象?
答案 0 :(得分:4)
首先,此代码具有未定义的行为,因为它将一个双字节数组重新解释为更大的struct
。因此,它正在写入已分配空间的末尾。您可以使用struct
的大小来声明buffer
数组,从而使您的程序有效,如下所示:
struct globals {
int value;
char type;
long tup;
};
char buffer[sizeof(struct globals)];
#define
正在以通常的方式工作 - 通过提供令牌G
的文本替换,就像您在自己喜欢的文本编辑器中运行搜索和替换一样。预处理器是C编译器的第一个阶段,它会查找每个条目G
,并将其替换为(*(struct globals*)&buffer)
。
预处理器完成后,编译器会看到以下代码:
int main ()
{
(*(struct globals*)&buffer).value = 233;
(*(struct globals*)&buffer).type = '*';
(*(struct globals*)&buffer).tup = 1234123;
printf("\nValue = %d\n",(*(struct globals*)&buffer).value);
printf("\ntype = %c\n",(*(struct globals*)&buffer).type);
printf("\ntup = %ld\n",(*(struct globals*)&buffer).tup);
return 0;
}
答案 1 :(得分:1)
宏只是将2个字符的缓冲区buf
的地址转换为指向相应结构类型的指针,然后取消引用它以生成结构类型的左值。这就是dot(.
)struct-access运算符在G
上工作的原因。
不知道为什么有人会这样做。当需要 时(在示例代码中“从不”,但可能是在较大的原始代码库中的某处使用),我认为转换为字符数组/从字符数组更清晰,或者使用union
来摆脱宏。
union {
struct {
int value;
/* ... */
} s;
char c[2];
} G;
G.s.value = 233; /* and so on */
既清洁又清晰。请注意,char
数组太小。