我可以验证预处理器宏以确保它是一个数字吗?

时间:2014-11-29 16:52:47

标签: c++ validation macros c-preprocessor

我正在使用宏来定义代码中的简单变量(类似这样):

#define foobar 1
//...
barfoo(foobar);

为了防止错误,我想通过验证输入来确保foobar是一个数字。 foobar应始终为数字,因此非常简单。

显然,预处理器不处理数学,所以任何用算术生成某种类型错误的希望都会丢失。

我认为常量因为这个原因确实更好,但我正在尝试使用所有宏,因此它在我拥有的配置文件中是一致的(有些需要宏)。正则表达式可能是一个好的解决方法,但是GCC似乎不支持[使用宏]这个(加上, http://xkcd.com/1171/ )。

4 个答案:

答案 0 :(得分:5)

在C ++ 11中,有类型特征和静态断言可以满足您的目的:

#include <type_traits>

#define foo 1
// #define foo "bar" // will lead to a compiler error containing the message "foo is not int"

static_assert(std::is_integral<decltype(foo)>::value, "foo is not int");

答案 1 :(得分:2)

由于对问题的评论说不应该禁止表达式,所以涉及编译时检查表达式具有整数类型的答案将不起作用:这将检测{{1}之间没有区别},1(1),因为这三个都是(0+1)类型的prvalues,具有完全相同的值。

因此,答案必须涉及查看宏定义本身,并且可以通过对其进行字符串化,并将验证放在带有字符串的int函数中,并在静态断言中使用它。正十进制非整数整数文字的示例:

constexpr

如果您还需要处理后缀文字(#define A 1 #define B 2 #define C 3 #define D (4) #define STR_(x) #x #define STR(x) STR_(x) constexpr bool is_number(const char *str) { return (*str >= '0' && *str <= '9') && (str[1] == '\0' || is_number(str+1)); } #define VERIFY(x) static_assert(is_number(STR(x)), STR(x) " is not a number!") VERIFY(A); // passes VERIFY(B); // passes VERIFY(C); // passes VERIFY(D); // fails: (4) is not a number! )或非十进制文字(123L),则需要进行扩展。如果作为特殊例外,您希望允许将一元0x123应用于整数文字,那么也需要扩展名。

这几乎肯定不值得保护。如果-定义为D(4)(3+1),而不是(C+1),则有人决定代码更具可读性和/或可维护性,如果除了这一断言之外,这些定义可以很好地起作用,那么断言就会很快被破坏掉。

答案 2 :(得分:1)

我建议你只在必要时使用宏,否则使用常量。一致性并不总是最重要的优先事项。

答案 3 :(得分:0)

为此目的,有充分的理由使用常量而不是定义。

Scott Meyers在他的“Effective C ++”一书中有一章专门讨论这个问题:
http://books.google.com/books?id=U7lTySXdFk0C&pg=PT41&lpg=PT41#v=onepage&q&f=false

第2项:“更喜欢#defines的consts,enums和inlines。”

使用常量可以使调试更容易,因为编译器可以访问名称(而不仅仅是预处理器替换)。

定义也没有相同的类型安全功能(这可能是你试图在这里解决的问题)。它们没有相同的范围特征。