为什么三元运算符用来在macros中定义1和0?
我正在使用一个embedded式项目的SDK。 在这个源代码中,我发现了一些至less我觉得奇特的代码。 在SDK中的很多地方都有这种格式的源代码:
#define ATCI_IS_LOWER( alpha_char ) ( ( (alpha_char >= ATCI_char_a) && (alpha_char <= ATCI_char_z) ) ? 1 : 0 ) #define ATCI_IS_UPPER( alpha_char ) ( ( (alpha_char >= ATCI_CHAR_A) && (alpha_char <= ATCI_CHAR_Z) ) ? 1 : 0 )
这里使用三元运算符有什么区别吗?
是不是
#define FOO (1 > 0)
一样
#define BAR ( (1 > 0) ? 1 : 0)
?
我试着用评估它
printf("%d", FOO == BAR);
并得到结果1,所以它们似乎是平等的。 有没有像他们这样写代码的理由?
你是对的,在C中是同源的。 你的特定的三元条件和 (1 > 0)
都是int
types的。
但是,在C ++中,在一些奇怪的angular落情况下(例如,作为重载函数的参数),这一点很重要,因为三元条件expression式的types是int
,而(1 > 0)
的types是bool
。
我的猜测是作者已经考虑到了这一点,着眼于保持C ++的兼容性。
有linting工具,认为比较的结果是布尔值,不能直接在算术中使用。
不要命名或指点任何手指,但PC-lint就是这样一个工具 。
我不是说他们是对的,但是为什么代码是这样写的,这是一个可能的解释。
有时你会用非常古老的代码看到这一点,从之前有一个C标准来说明(x > y)
计算为数字1或0; 有些CPU宁愿将其评估为-1或0,而一些非常老的编译器可能也只是跟随而已,所以一些程序员觉得需要额外的防御。
你有时也会看到这个,因为类似的expression式不一定要求数字1或0.例如,在
#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) ? 1 : 0)
内部&
expression式的计算结果为0或F_DO_GRENFELZ
的数值,可能不是 1,所以? 1 : 0
? 1 : 0
用于规范化它。 我个人认为把它写得更清楚
#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) != 0)
但合理的人可以不同意。 如果你连续testing了一大堆这样的expression式,那么有人可能已经决定把它放在更易维护的地方了? 1 : 0
? 1 : 0
的结局,而不是担心哪些实际需要它。
SDK代码中存在一个错误,三元组可能是一个修复它的问题。
作为macros的参数(alpha_char)可以是任何expression式,并且应该加上括号,因为像'A'&&'c'这样的expression式将会使testing失败。
#define IS_LOWER( x ) ( ( (x >= 'a') && (x <= 'z') ) ? 1 : 0 ) std::cout << IS_LOWER('A' && 'c'); **1** std::cout << IS_LOWER('c' && 'A'); **0**
这就是为什么一个人总是在扩展中将macros参数括起来的原因。
所以在你的例子(但有参数),这些都是窃听。
#define FOO(x) (x > 0) #define BAR(x) ((x > 0) ? 1 : 0)
他们将被正确地取代
#define BIM(x) ((x) > 0)
@CiaPan在使用参数不止一次导致未定义结果的评论中做了一个很好的观点。 例如
#define IS_LOWER( x ) (((x) >= 'a') && ((x) <= 'z')) char ch = 'y'; std::cout << IS_LOWER(ch++); **1** **BUT ch is now '{'**
在C中并不重要。 C中的布尔expression式的types为int
,值为0
或1
,所以
ConditionalExpr ? 1 : 0
没有效果。
在C ++中,它实际上是对int
,因为C ++中的条件expression式具有typesbool
。
#include <stdio.h> #include <stdbool.h> #ifndef __cplusplus #define print_type(X) _Generic(X, int: puts("int"), bool: puts("bool") ); #else template<class T> int print_type(T const& x); template<> int print_type<>(int const& x) { return puts("int"); } template<> int print_type<>(bool const& x) { return puts("bool"); } #endif int main() { print_type(1); print_type(1 > 0); print_type(1 > 0 ? 1 : 0); /*c++ output: int int int cc output: int bool int */ }
也可能没有任何效果,作者简单地认为它使代码更清晰。
一个简单的解释是有些人不明白一个条件会在C中返回相同的值,或者他们认为写入更清晰((a>b)?1:0)
。
这就解释了为什么一些人在使用适当的布尔语的语言中也使用类似的结构,这在C语法中是(a>b)?true:false)
。
这也解释了为什么你不应该不必要地改变这个macros。
也许,作为一个embedded式软件,会给出一些线索。 也许有很多macros使用这种风格编写,容易提示ACTI行使用直接逻辑而不是倒置逻辑。