为什么三元运算符用于在宏中定义1和0?

时间:2017-03-31 11:06:32

标签: c++ c boolean ternary-operator

我正在为嵌入式项目使用SDK。在这个源代码中,我发现了一些代码,至少我发现这些代码很奇怪。在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,所以看起来它们是平等的。是否有理由像他们一样编写代码?

7 个答案:

答案 0 :(得分:132)

你是对的,在C中它是同义的。您的特定三元条件 (1 > 0)都属于int类型。

但它在中在C ++中很重要,但是在一些奇怪的极端情况下(例如作为重载函数的参数),因为你的三元条件表达式是int类型,而{{1类型为(1 > 0)

我的猜测是作者对此有所考虑,着眼于保持C ++兼容性。

答案 1 :(得分:29)

有些linting工具认为比较的结果是布尔值,不能直接用于算术。

不是为姓名命名或指向任何手指,而是PC-lint is such a linting tool

我不是说他们是对的,但这可能解释为什么代码是这样编写的。

答案 2 :(得分:20)

您有时会在非常旧的代码中看到这一点,从之前有一个C标准来说明while评估为数字1或0;一些CPU宁愿将其评估为-1或0,而一些非常旧的编译器可能只是跟随,所以一些程序员认为他们需要额外的防御性。

您有时也会看到这一点,因为类似的表达式必须评估为数字1或0.例如,在

(x > y)

内部#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) ? 1 : 0) - 表达式的计算结果为0或&的数值,可能 1,因此F_DO_GRENFELZ用于规范化它。我个人认为把它写成

更清楚
? 1 : 0

但合理的人可以不同意。如果你连续测试了大量这些,测试不同类型的表达式,有人可能会认为将#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) != 0) 放在所有的末尾比将其维护得更容易。担心哪些人真的需要它。

答案 3 :(得分:16)

SDK代码中存在一个错误,而三元可能是解决它的一个问题。

作为一个宏,参数(alpha_char)可以是任何表达式,并且应该用括号括起来,因为表达式如&#39; A&#39; &安培;&安培; &#39; C&#39;将无法通过测试。

#define IS_LOWER( x ) ( ( (x >= 'a') && (x <= 'z') ) ?  1 : 0 )
std::cout << IS_LOWER('A' && 'c');
**1**
std::cout << IS_LOWER('c' && 'A');
**0**

这就是为什么人们应该总是在扩展中括起宏参数。

所以在你的例子中(但有参数),这些都是错误的。

#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 '{'**

答案 4 :(得分:5)

在C中它并不重要。 C中的布尔表达式的类型为int,其值为01,所以

ConditionalExpr ? 1 : 0

没有效果。

在C ++中,它实际上是对int的强制转换,因为C ++中的条件表达式具有类型bool

#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
*/

}

它也可能没有效果,作者只是认为它使代码更清晰。

答案 5 :(得分:5)

一个简单的解释是,有些人要么不明白条件会在C中返回相同的值,要么他们认为写((a>b)?1:0)更清楚。

这解释了为什么有些人也会在具有适当布尔值的语言中使用类似的结构,这在C语法中将是(a>b)?true:false)

这也解释了为什么你不应该不必要地改变这个宏。

答案 6 :(得分:0)

也许,作为一个嵌入式软件,会给出一些线索。也许有许多使用这种风格编写的宏,很容易暗示ACTI行使用直接逻辑而不是反向逻辑。