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

Can I validate a preprocessor macro to make sure it's a number?

本文关键字:一个 数字 验证 预处理 处理器 确保 是否      更新时间:2023-10-16

我正在使用宏在我的代码中定义简单的变量(如下所示):

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

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

显然,预处理器不处理数学,因此失去了用算术生成某种类型错误的希望。

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

在 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(1)(0+1)之间没有区别,因为这三个都是具有完全相同值的 int 类型的 pr值。

因此,答案必须涉及查看宏定义本身,这可以通过将其字符串化,并将验证放在接受字符串的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] == '' || 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),而不是4,如果除了这个断言之外,这些定义将很好地工作,断言很快就会从代码中剥离出来。

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

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

斯科特·迈耶斯(Scott Meyers)在他的《有效C++》一书中有一章专门讨论这一点:
http://books.google.com/books?id=U7lTySXdFk0C&pg=PT41&lpg=PT41#v=onepage&q&f=false

第 2 项:"首选常量、枚举和内联而不是 #defines"。

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

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