比较平等preprocessor宏 [英] Compare preprocessor macros for equality
问题描述
我有一些 .DBC
文件的一些原油生成的头。
由于几个消息从一个阵列重新present要素结构是相等的,因此所产生的宏是相等的。由于我补结构的一些数组中的code,我想省力,并使用相同的宏对所有对象,但要保证这些定义都没有改变,我想在编译时测试如果宏是相等的。
I have some crude generated header from some .dbc
files.
Since a few of the messages represent elements from an array the structure is equal and so the generated Macros are equal. Since I fill some array of struct in the code I would like to save effort and use the same macro for all objects, but to ensure the definitions have not changed I would like to test at compile time if the macros are equal.
例如:
#define GET_PATTERN_01_PATTERNPOINT02Y(buf) (0 \
| (uint16)(-(uint16)((buf[7] >> 6) & 0x01) << 15) \
| (uint8)(+(uint8)((buf[6] >> 0) & 0xff) << 0) \
| (uint16)(+(uint16)((buf[7] >> 0) & 0x7f) << 8) \
)
#define GET_PATTERN_02_PATTERNPOINT04Y(buf) (0 \
| (uint16)(-(uint16)((buf[7] >> 6) & 0x01) << 15) \
| (uint8)(+(uint8)((buf[6] >> 0) & 0xff) << 0) \
| (uint16)(+(uint16)((buf[7] >> 0) & 0x7f) << 8) \
)
#if GET_PATTERN_01_PATTERNPOINT02Y != GET_PATTERN_02_PATTERNPOINT04Y
# error blah
#endif
这可能吗?
如果在C ++的一些解决方案,也可能会有帮助。但宏是固定的。
Is this Possible? If there is some solution in C++ that may also help. But the macros are fixed.
推荐答案
这是一个可怕的黑客,但似乎你比如GCC和C11至少工作:
This is a horrible hack, but seems to work for your example for GCC and C11 at least:
#include <assert.h>
#include <string.h>
...
#define STRINGIFY(x) STRINGIFY_(x)
#define STRINGIFY_(x) #x
#define ASSERT_SAME(m1, m2) \
static_assert(strcmp(STRINGIFY(m1(xxx)), STRINGIFY(m2(xxx))) == 0, \
#m1"() and "#m2"() differ!")
ASSERT_SAME(GET_PATTERN_01_PATTERNPOINT02Y, GET_PATTERN_02_PATTERNPOINT04Y);
您可能需要通过 -std = C11
或 -std = gnu11
,尽管后者不应该在这里需要的。
You might need to pass -std=c11
or -std=gnu11
, though the latter shouldn't be needed here.
说明:
-
字符串化(X)
返回X
作为一个字符串字面量的扩张。我们需要使用做字符串化分两步字符串化_()
,因为#
燮presses宏扩展。 (有一个步骤中,我们会得到&LT; X&gt;中
而不是扩大版&LT; X&gt;中
)
STRINGIFY(x)
returns the expansion ofx
as a string literal. We need to do the stringification in two steps usingSTRINGIFY_()
because#
suppresses macro expansion. (With one step we'd get"<x>"
instead of"expanded version of <x>"
.)
GCC有一个内置的版本的strcmp()
( __ builtin_strcmp()
),这是用在这里。这恰好是能够常量字符串在编译时进行比较。在code休息,如果你通过 -fno-内置
(除非你明确地用 __ builtin_strcmp()
)
GCC has a built-in version of strcmp()
(__builtin_strcmp()
) which is used here. It just happens to be able to compare constant strings at compile-time. The code breaks if you pass -fno-builtin
(unless you explicitly use __builtin_strcmp()
).
static_assert
是C11编译时断言。
static_assert
is a C11 compile-time assertion.
随着三种成分上面我们可以将字符串化扩展宏(通过一些虚拟令牌很可能是对的说法是唯一的),并在编译时比较字符串。
With the three ingredients above we can stringify the expanded macros (passing some dummy token that's likely to be unique for the argument) and compare the strings at compile-time.
是的,这是一个黑客...
Yes, this is a hack...
在C ++ 11有更安全的方式来比较在编译时间字符串 - 例如见<一href=\"http://stackoverflow.com/questions/27490858/how-can-you-compare-two-character-strings-statically-at-compile-time\">this回答。
In C++11 there are safer ways to compare strings at compile time -- see e.g. this answer.
作为一个方面说明,你可以在运行时零开销GCC和锵做到这一点。 (以上版本不会为锵工作,因为它是关于挑剔的strcmp(...)== 0
不是一个整型常量前pression 的所要求的 static_assert
)。一个运行时检查像
As a side note, you could do this at run-time too with zero overhead for GCC and Clang. (The version above won't work for Clang as it's pickier about strcmp(...) == 0
not being an integer constant expression as required by static_assert
.) A run-time check like
if (strcmp(STRINGIFY(m1(xxx)), STRINGIFY(m2(xxx))) != 0) {
*report error and exit*
}
得到完全优化出来的时候,宏是相等的。甚至不是字符串保存在只读数据段(只需选中)。这是一个更强大的方法,如果你可以不必运行程序,以发现问题现场。
gets completely optimized out when the macros are equal. Not even the strings are kept in the read-only data segment (just checked). It's a more robust approach if you can live with having to run the program to discover the problem.
这篇关于比较平等preprocessor宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!