- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想预先澄清这一点:我知道这个技巧是如何工作的,我想要的是一个指向清晰解释的链接以与其他人分享。
C macro question 的答案之一谈论“X 宏”或“尚未定义的宏”习语。这涉及定义如下内容:
#define MAGIC_LIST \
X(name_1, default_1) \
X(name_2, default_2) \
...
然后,要创建一个具有命名索引的值数组,您可以执行以下操作:
typedef enum {
#define X(name, val) name,
MAGIC_LIST
#undef X
} NamedDefaults;
您可以使用不同的 #define
为 X()
重复该过程,以创建值数组,并可能调试字符串等。
我想要一个关于其工作原理的清晰解释的链接,该链接是针对对 C 还算熟悉的人。不过,我不知道每个人通常如何称呼这种模式,因此我在网络上搜索它的尝试到目前为止都失败了。
(如果SO有这样的解释就好了...)
最佳答案
关于 C 预处理器的维基百科页面提到了它,但在我看来并不是非常清楚: http://en.wikipedia.org/wiki/C_preprocessor#X-Macros
我为我的团队写了一篇关于它的论文;如果您愿意,请随意使用它。
/* X-macros are a way to use the C pre-processor to provide tuple-like
* functionality that would not otherwise be easy to implement in C.
* Any time you find yourself writing a comment that says something
* like "These values must be kept in sync with the values in typedef enum
* foo_t", or adding a new item to a list and copying and pasting functions
* to handle it, then X-macros are probably a better way to implement the
* behaviour you want.
*/
/* Begin with the main definition of the table of tuples. This can be directly
* in the header file, or in a separate #included template file. This example
* is from some hardware revision reporting code.
*/
/*
* Board versions
* Upper bound resistor value, hardware version, hardware version string
*/
#define APP_HW_VERSIONS \
X(0, HW_UNKNOWN, UNKNOWN_HW_VER) \
X(8, HW_NO_VERSION, "XDEV") /* Unversioned board (e.g. dev board) */ \
X(24, HW_REVA, "REVA") \
X(39, HW_REVB, "REVB") \
X(54, HW_REVD, "REVD") \
X(71, HW_REVE, "REVE") \
X(88, HW_REVF, "REVF") \
X(103,HW_REVG, "REVG") \
X(118,HW_REVH, "REVH") \
X(137,HW_REVI, "REVI") \
X(154,HW_REVJ, "REVJ") \
/* add new versions above here */ \
X(255,HW_REVX, "REVX") /* Unknown newer version */
/* Now, any time you need to use the contents of this table, you redefine the
* X(a,b,c) macro to give the behaviour you want. In the hardware revision
* example, the first thing we need is an enumerated type giving the
* possible options for the value of the hardware revision.
*/
#define X(a,b,c) b,
typedef enum {
APP_HW_VERSIONS
} app_hardware_version_t;
#undef X
/* The next thing we need in this example is some code to extract the
* hardware revision from the value of the version resistors.
*/
static app_hardware_version_t read_board_version(
board_aio_id_t identifier,
board_aio_val_t value
)
{
app_hardware_version_t app_hw_version;
/* Determine board version based on ADC reading */
#define X(a,b,c) if (value < a) {app_hw_version = b;} else
APP_HW_VERSIONS
#undef X
{
app_hw_version = HW_UNKNOWN;
}
return app_hw_version;
}
/* Now we have two different places that need to extract the hardware revision
* as a string: the MMI info screen and the ATI command.
*/
/* in the info screen code: */
switch(ver)
{
#define X(a,b,c) case b: ascii_to_display_string((lcd_char_t *) &app[0], c, HW_VER_STRING_LEN); break;
APP_HW_VERSIONS
#undef X
default:
ascii_to_display_string((lcd_char_t *) &app[0], UNKNOWN_HW_VER, HW_VER_STRING_LEN);
break;
}
/* in the ATI handling code: */
switch(ver)
{
#define X(a,b,c) case b: strncpy(&p_data, (const uint8_t *) c, HW_VER_STRING_LEN); break;
APP_HW_VERSIONS
#undef X
default:
strncpy_write(&p_data, (const uint8_t *) UNKNOWN_HW_VER, HW_VER_STRING_LEN);
break;
}
/* Another common example use case is auto-generation of accessor and mutator
* functions for a list of storage keys
*/
/* First the tuple table */
/* Configuration items:
* Storage key ID, name, type, min value, max value
*/
#define CONFIG_ITEMS \
X(1234, DEVICE_ID, uint16_t, 0, 0xFFFF) \
X(1235, NUM_CONNECTIONS, uint8_t, 0, 8) \
X(1236, ENABLE_LOGGING, bool_t, 0, 1) \
X(1237, SECURITY_KEY, uint32_t, 0, 0xFFFFFFFF)
/* add new items above here */
/* Generate the enumerated type of keys */
#define X(a,b,c,d,e) CONFIG_ITEM_##b = a,
typedef enum {
CONFIG_ITEMS
} config_item_t;
#undef X
/* Generate the accessor functions */
#define X(a,b,c,d,e) \
int get_config_item_##b(void *p_buf) \
{ \
return read_from_key(a, sizeof(c), p_buf); \
}
CONFIG_ITEMS
#undef X
/* Generate the mutator functions */
#define X(a,b,c,d,e) \
bool_t set_config_item_##b(void *p_buf) \
{ \
c val = * (c*) p_buf; \
if (val < d || val > e) return FALSE; \
return write_to_key(a, sizeof(c), p_buf); \
}
CONFIG_ITEMS
#undef X
/* Or, if you prefer, one big generic accessor function */
int get_config_item(config_item_t id, void *p_buf)
{
switch (id)
{
#define X(a,b,c,d,e) case a: return read_from_key(a, sizeof(c), p_buf); break;
CONFIG_ITEMS
#undef X
default:
return 0;
}
}
/* and one big generic mutator function */
bool_t set_config_item(config_item_t id, void *p_buf)
{
switch (id)
{
#define X(a,b,c,d,e) \
case a: \
{ \
c val = * (c*) p_buf; \
if (val < d || val > e) return FALSE; \
return write_to_key(a, sizeof(c), p_buf); \
}
CONFIG_ITEMS
#undef X
default:
return FALSE;
}
}
/* Finally let's add a logging function to dump all the config items */
void log_config_items(void)
{
#define X(a,b,c,d,e) \
{ \
c val; \
if (read_from_key(a, sizeof(c), &val) == sizeof(c)) \
{ printf("CONFIG_ITEM_##b (##a): 0x%x\n", val); } \
else { printf("CONFIG_ITEM_##b (##a): Failed to read\n"); } \
}
CONFIG_ITEMS
#undef X
}
/* Now, when you need to add a new item to your list of config keys, you don't
* need to update the enumerated type and copy and paste new get and set
* functions for each new key; you simply update the table of tuples and the
* pre-processor takes care of the rest.
*/
关于c - 寻找表生成宏惯用语的良好解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2927245/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!