使用#define定义struct对象

时间:2014-04-28 10:14:13

标签: c c-preprocessor

我偶然发现了这个简单的程序

#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类型的对象?

2 个答案:

答案 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数组太小。