比较运算符

来自cppreference.com
< c‎ | language

比较运算符是二元运算符,它们测试条件,而若条件逻辑上为则返回 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 可转换为 double ,二个 4.0 比较相等
 
    struct { int x,y; } s;
    assert(&s.x < &s.y); // 结构体成员以声明顺序比较
 
    double d = 0.0/0.0; // NaN
    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); // 不同值
}

等于运算符

等于运算符拥有形式

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 的指针,故 C 中可定义宏 NULL(void*)0 ,不过 C++ 中这会非法,因为其中 void 指针不可隐式转换为有类型指针。

比较浮点值是否相等时应谨慎,因为许多运算的结果无法准确表示,而必须舍入。实践中,通常以允许最后位置相差一或多个单位的方式比较浮点数。

#include <assert.h>
int main(void)
{
    assert(2+2 == 4.0); // int 可转换为 double ,二个 4.0 比较相等
 
    int n[2][3] = {1,2,3,4,5,6};
    int* p1 = &n[0][2]; // 第一栏中的最后元素
    int* p2 = &n[1][0]; // 第二栏的起始
    assert(p1+1 == p2); // 比较相等
 
    double d = 0.0/0.0; // NaN
    assert( d != d ); // NaN 不等于自身
 
    float f = 0.1; // f = 0.100000001490116119384765625
    double g = 0.1; // g = 0.1000000000000000055511151231257827021181583404541015625
    assert(f != g); // 不同值
}

引用

  • C17 标准(ISO/IEC 9899:2018):
  • 6.5.8 Relational operators (第 68-69 页)
  • 6.5.9 Equality operators (第 69-70 页)
  • C11 标准(ISO/IEC 9899:2011):
  • 6.5.8 Relational operators (第 95-96 页)
  • 6.5.9 Equality operators (第 96-97 页)
  • C99 标准(ISO/IEC 9899:1999):
  • 6.5.8 Relational operators (第 85-86 页)
  • 6.5.9 Equality operators (第 86-87 页)
  • C89/C90 标准(ISO/IEC 9899:1990):
  • 3.3.8 Relational operators
  • 3.3.9 Equality operators

参阅

运算符优先级

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

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
? :
sizeof
_Alignof
(C11 起)