由头文件中的语言数据类型声明的struct变量。通常数据类型用于声明变量,但其他数据类型传递给预处理器。当我们应该使用数据类型发送到预处理器来声明变量?为什么数据类型和变量会发送到处理器?
#define DECLARE_REFERENCE(type, name) \
union { type name; int64_t name##_; }
typedef struct _STRING
{
int32_t flags;
int32_t length;
DECLARE_REFERENCE(char*, identifier);
DECLARE_REFERENCE(uint8_t*, string);
DECLARE_REFERENCE(uint8_t*, mask);
DECLARE_REFERENCE(MATCH*, matches_list_head);
DECLARE_REFERENCE(MATCH*, matches_list_tail);
REGEXP re;
} STRING;
答案 0 :(得分:1)
为什么此代码正在为声明执行此操作?因为正如DECLARE_REFERENCE
的主体所示,当一个类型和名称被传递给这个宏时,它不仅仅是声明 - 它还会在名称之外构建其他东西,用于其他一些未知目的。如果只想要声明一个变量,那么你就不会这样做 - 它只是简单地声明一个变量。
它实际上做了什么?宏声明的联合提供了第二个名称,用于访问相同的空间作为不同的类型。在这种情况下,您可以获取引用本身,或者也可以获取其位模式的未转换整数表示。假设int64_t
与目标上的指针大小相同,无论如何。
使用宏来实现这个目的可能有几个目的,我可以想到这一点:
你应该这样做吗?不。这不仅仅是声明变量,还做了其他事情,而其他事情显然特定于包含程序其余部分的血腥内部。如果没有看到程序的其余部分,我们可能永远不会完全理解它的其余部分。
当你需要针对你的程序的内部做一些特定的事情时,你(希望)知道什么时候发明你自己的东西 - 就像这样(很可能永远不会);但不要复制别人。
因此,这里的总体教训是确定人们不是直接编写C的地方,而是编写特定应用程序的编码,并将这两者分开,而不是将特定程序中的怪癖作为语言的指导。一个整体。
答案 1 :(得分:0)
有时需要保证一些声明可以保证彼此之间有某种关系。一些简单的关系,例如需要连续编号的常量,可以使用enum
声明来处理,但是某些应用程序需要更复杂的关系,而编译器无法直接处理这些关系。例如,可能希望有一组枚举值和一组字符串文字,并确保它们保持彼此同步。如果有人宣称:
#define GENERATE_STATE_ENUM_LIST \
ENUM_LIST_ITEM(STATE_DEFAULT, "Default") \
ENUM_LIST_ITEM(STATE_INIT, "Initializing") \
ENUM_LIST_ITEM(STATE_READY, "Ready") \
ENUM_LIST_ITEM(STATE_SLEEPING, "Sleeping") \
ENUM_LIST_ITEM(STATE_REQ_SYNC, "Starting synchronization") \
// This line should be left blank except for this comment
然后代码可以使用GENERATE_STATE_ENUM_LIST
宏来声明enum
类型和字符串数组,并确保即使从列表中添加或删除项目,每个字符串也会与其正确匹配枚举值。相反,如果数组和枚举声明是分开的,则向一个而不是另一个添加新状态可能导致值“不同步”。
我不确定特定情况下宏的用途是什么,但模式有时可能是合理的。最大的“问题”是(ab)使用C预处理器是否更好,以便允许这种关系以有效但丑陋的C代码表示,或者使用其他工具获取列表是否更好状态并将从中生成适当的C代码。