命名空间
变体
操作

比较运算符

来自 cppreference.cn
< c‎ | 语言

比较运算符是二元运算符,用于测试条件,如果条件在逻辑上为则返回1,如果条件为则返回0

运算符 运算符名称 示例 描述
== 等于 a == b a 等于 b
!= 不等于 a != b a 不等于 b
< 小于 a < b a 小于 b
> 大于 a > b a 大于 b
<= 小于或等于 a <= b a 小于或等于 b
>= 大于或等于 a >= b a 大于或等于 b

目录

[编辑] 关系运算符

关系运算符表达式的形式为

lhs < rhs (1)
lhs > rhs (2)
lhs <= rhs (3)
lhs >= rhs (4)
1) 小于表达式
2) 大于表达式
3) 小于或等于表达式
4) 大于或等于表达式

其中

lhs, rhs - 表达式,它们要么都是实数类型,要么都是指向对象类型的指针

任何关系运算符表达式的类型都是 int,其值(不是左值)在指定关系为真时为 1,在指定关系不为真时为 0

如果 lhsrhs 都是任何实数类型的表达式,则

  • 执行常用算术转换
  • 转换后的操作数的值按通常的数学意义进行比较(正零和负零比较相等,任何涉及 NaN 值的比较返回零)

请注意,复数和虚数不能用这些运算符进行比较。

如果 lhsrhs 都是指针类型的表达式,则它们必须都是指向兼容类型对象的指针,但忽略所指向对象的限定符。

  • 指向不是数组元素的对象的指针被视为指向只有一个元素的数组的元素
  • 如果两个指针指向同一个对象,或者都指向同一个数组的末尾之后一个位置,则它们比较相等
  • 如果两个指针指向同一个数组的不同元素,则指向索引较大的元素的指针比较大。
  • 如果一个指针指向数组的元素,而另一个指针指向同一个数组的末尾之后一个位置,则指向末尾之后一个位置的指针比较大
  • 如果两个指针指向同一个结构体的成员,则指向在结构体定义中声明在后面的成员的指针比较大,而不是指向在前面声明的成员的指针。
  • 指向同一联合体成员的指针比较相等
  • 所有其他指针比较都会导致未定义行为
#include <assert.h>
int main(void)
{
    assert(1 < 2);
    assert(2+2 <= 4.0); // int converts to double, two 4.0's compare equal
 
    struct { int x,y; } s;
    assert(&s.x < &s.y); // struct members compare in order of declaration
 
    double d = 0.0/0.0; // NaN
    assert( !(d < d) );
    assert( !(d > d) );
    assert( !(d <= d) );
    assert( !(d >= d) );
    assert( !(d == d) );
 
    float f = 0.1; // f = 0.100000001490116119384765625
    double g = 0.1; // g = 0.1000000000000000055511151231257827021181583404541015625
    assert(f > g); // different values
}

[编辑] 相等运算符

相等运算符表达式的形式为

lhs == rhs (1)
lhs != rhs (2)
1) 等于表达式
2) 不等于表达式

其中

lhs, rhs - 表达式,它们
(自 C23 起)
  • 都是指向对象或函数的兼容类型的指针,忽略所指向类型的限定符
  • 一个是指向对象的指针,另一个是指向(可能受限定的)void 的指针
  • 一个是指向对象或函数的指针,另一个是空指针常量,例如 NULL nullptr(C23 起)

任何相等运算符表达式的类型都是 int,其值(不是左值)在指定关系为真时为 1,在指定关系不为真时为 0

  • 如果两个操作数都具有算术类型,则执行常用算术转换,并按通常的数学意义比较结果值(正零和负零比较相等,任何涉及 NaN 值的比较,包括与自身的相等比较,都返回零)。特别是,如果复数类型的实部比较相等且虚部比较相等,则它们相等。
(自 C23 起)
  • 如果一个操作数是指针,另一个是空指针常量,则空指针常量首先转换为指针的类型(这会给出空指针值),然后按如下所述比较这两个指针
  • 如果一个操作数是指针,另一个是指向 void 的指针,则非 void 指针转换为指向 void 的指针,然后按如下所述比较这两个指针
  • 如果满足以下任何条件,则两个指针比较相等
  • 它们都是其类型的空指针值
  • 它们都指向同一个对象或函数
  • 一个指针指向结构体/联合体/数组对象,另一个指针指向其第一个成员/任何成员/第一个元素
  • 它们都指向同一个数组的最后一个元素之后一个位置
  • 一个指针指向数组的末尾之后一个位置,另一个指针指向在较大数组中或没有填充的结构体中紧随第一个数组的不同数组(相同类型)的开头

(与关系运算符一样,指向不是任何数组元素的对象的指针的行为与指向大小为 1 的数组元素的指针相同)

[编辑] 注释

结构体类型的对象不会自动比较相等,并且使用 memcmp 比较它们并不可靠,因为填充字节可能具有任何值。

由于指针比较适用于指向 void 的指针,宏 NULL 在 C 语言中可以定义为 (void*)0,尽管这在 C++ 中是无效的,因为 void 指针不会隐式转换为类型化指针

在比较浮点数值的相等性时必须小心,因为许多操作的结果无法精确表示,必须进行舍入。实际上,浮点数通常会进行比较,允许一个或多个末尾单位的差异。

#include <assert.h>
int main(void)
{
    assert(2+2 == 4.0); // int converts to double, two 4.0's compare equal
 
    int n[2][3] = {1,2,3,4,5,6};
    int* p1 = &n[0][2]; // last element in the first row
    int* p2 = &n[1][0]; // start of second row
    assert(p1+1 == p2); // compare equal
 
    double d = 0.0/0.0; // NaN
    assert( d != d ); // NaN does not equal itself
 
    float f = 0.1; // f = 0.100000001490116119384765625
    double g = 0.1; // g = 0.1000000000000000055511151231257827021181583404541015625
    assert(f != g); // different values
}

[编辑] 参考

  • C17 标准 (ISO/IEC 9899:2018)
  • 6.5.8 关系运算符 (p: 68-69)
  • 6.5.9 相等运算符 (p: 69-70)
  • C11 标准 (ISO/IEC 9899:2011)
  • 6.5.8 关系运算符 (p: 95-96)
  • 6.5.9 相等运算符 (p: 96-97)
  • C99 标准 (ISO/IEC 9899:1999)
  • 6.5.8 关系运算符 (p: 85-86)
  • 6.5.9 相等运算符 (p: 86-87)
  • C89/C90 标准 (ISO/IEC 9899:1990)
  • 3.3.8 关系运算符
  • 3.3.9 相等运算符

[编辑] 另请参见

运算符优先级

常见运算符
赋值 递增
递减
算术 逻辑 比较 成员
访问
其他

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
a ? b : c
sizeof


_Alignof
(C11 起)
(直至 C23)

alignof
(自 C23 起)

C++ 文档,关于比较运算符