天道酬勤,学无止境

std::less 是否必须与指针类型的相等运算符一致?(Does std::less have to be consistent with the equality operator for pointer types?)

问题

我昨天遇到了一个问题,我最终将其提炼为以下最小示例。

#include <iostream>
#include <functional>

int main()
{
    int i=0, j=0;
    std::cout
        << (&i == &j)
        << std::less<int *>()(&i, &j)
        << std::less<int *>()(&j, &i)
        << std::endl;
}

这个特定的程序,当使用启用优化的 MSVC 9.0 编译时,输出000 。 这意味着

  1. 指针不相等,并且
  2. 根据std::less ,两个指针都不在另一个之前排序,这意味着根据std::less施加的总顺序,这两个指针是相等的。

这种行为正确吗? std::less的总顺序不需要与相等运算符一致吗?

以下程序是否允许输出1

#include <iostream>
#include <set>

int main()
{
    int i=0, j=0;
    std::set<int *> s;
    s.insert(&i);
    s.insert(&j);
    std::cout << s.size() << std::endl;
}
回答1

似乎我们有一个标准的违反! 恐慌!

以下20.3.3 / 8(C ++ 03):

对于更大、更少、greater_equal 和less_equal 模板,任何指针类型的特化都会产生一个总顺序,即使内置运算符<、>、<=、>= 没有。

这似乎是一个情况下急于优化导致错误代码......

编辑:的C ++ 0x也保持该一个20.8.5 / 8下

编辑2:奇怪的是,作为第二个问题的答案:

继 5.10/1 C++03 之后:

同一类型的两个指针比较相等当且仅当它们都为null,都指向相同的功能,或两者都代表相同的地址

这里出了点问题……在很多层面上。

回答2

不,结果显然不正确。

但是,众所周知,MSVC 不会严格遵守“唯一地址”规则。 例如,它合并了恰好生成相同代码的模板函数。 那么那些不同的函数也将具有相同的地址。

我想如果您实际上对 i 和 j 做了一些事情,而不是获取他们的地址,那么您的示例会更好。

标签

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 比较指向不同数组的指针是否相等,这是否是未指定的行为?(Is it unspecified behavior to compare pointers to different arrays for equality?)
    问题 相等运算符在指针上具有关系运算符的语义限制: ==(等于)和!=(不等于)运算符与关系运算符具有相同的语义限制,转换和结果类型,但它们的优先级和真值结果较低。 [C ++ 03§5.10p2] 关系运算符在比较指针方面有一个限制: 如果两个相同类型的指针p和q指向不同的对象,这些对象不是同一对象的成员,也不是同一数组的元素,或者指向不同的函数,或者如果其中只有一个为空,则p <q,p的结果未指定> q,p <= q和p> = q。 [§5.9p2] 这是相等运算符“继承”的语义限制吗? 具体来说,给出: int a[42]; int b[42]; 显然(a + 3)<(b + 3)是未指定的,但是(a + 3)==(b + 3)也是未指定的吗? 回答1 op==和op!=的语义明确表示映射是它们的真值结果除外。 因此,您需要查看为其真值结果定义的内容。 如果他们说结果未指定,则结果未指定。 如果他们定义了特定规则,那么就没有。 特别是说 当且仅当两个指针都为null,都指向相同的函数或都表示相同的地址时,两个相同类型的指针才会比较相等 回答2 只要指针指向相同类型的对象,相等运算符( ==和!= )的结果就会产生指定的结果。 给定两个指向相同类型的指针,以下条件之一就是正确的: 两者都是空指针,并且彼此比较相等。 两者都是指向同一对象的指针,并且彼此比较相等。
  • 将 std::less 与 nullptr 一起使用(Using std::less with nullptr)
    问题 以下代码片段中的断言是否始终成立? std::less<Object *> lessPtr; Object * o = new Object(); assert(lessPtr (o, nullptr) == false); 回答1 介绍 这个问题实际上归结为在一个操作数为nullptr指针类型上使用小于关系运算符是否会产生“预期”结果; 可悲的是,情况并非如此。 结果是不确定的。 注意:请注意std::less保证总顺序; 这意味着即使在使用函数对象时结果是unspecified ,它也必须在每次调用时产生相同的unspecified值。 国际标准 (N3337) 怎么说? 5.9p2关系运算符[expr.rel] 可以比较指向相同类型的对象或函数的指针(指针转换后),结果定义如下: 如果相同类型的两个指针p和q指向同一个对象或函数,或者都指向同一个数组的末尾,或者都为空,则p<=q和p>=q都产生true和p<q和p>q都产生false 。 如果两个相同类型的指针p和q指向不同的对象,这些对象不是同一对象的成员或同一数组的元素或不同的函数,或者只有其中一个为空,则p<q , p>q 、 p<=q和p>=q未指定。 如果两个指针指向同一对象的非静态数据成员,或者指向这些成员的子对象或数组元素,递归地,如果两个成员具有相同的访问控制(第 11 条)和前提是他们的班级不是工会。
  • 指针上的运算符<(小于)是否一致?(Is operator< (less than) on pointers consistent?)
    问题 注意:这个问题与总订单无关。 可以使用std::less获得相同类型指针的总顺序。 据此,如果两个指针指向不同的分配,则不允许将两个指针与operator<进行比较。 在哪个意义上是不允许的? 它是实现定义的、未指定的或未定义的行为吗? 我想我在某处读到它是未指定的。 实现不需要记录行为是什么,但必须有一些行为。 所以这意味着,比较任何两个指针仍然是合法的,但不一定会产生总顺序。 这是否意味着,当比较相同的两个指针两次时,我们仍然必须得到一致的结果? 一般情况是:在应用程序中两次调用相同的未指定行为是否总是产生相同的结果? int i1, i2; int* a = &i1; int* b = &i2; bool b1 = a < b; // unspecified, right? bool b2 = a < b; assert(b1 == b2); // Is this guaranteed to be true? 回答1 比较两个不相关的指针(即指针不指向同一内存,或不指向同一“数组”的不同部分)只能使用等式==和不等式!=来完成。 所有其他比较均未指定。 如果你有两个指针指向同一个地方,或者在同一个数组中,那么你可以使用相对运算符来比较它们。 所以如果你有例如 int* p1 = new int[10]; int* p2 = new int[5]; 您只能使用==和
  • 检查子对象的地址是否在包含对象的边界内是否合法(Is it legal to check whether the address of a subobject lies within the bounds of a containing object)
    问题 2 问题: 以下代码格式是否符合定义的行为? 是否有任何可能的 C++ 实现可以断言? 代码(c++11 及更高版本): #include <cassert> #include <utility> #include <ciso646> template<class T> auto to_address(T* p) { return reinterpret_cast<unsigned char const*>(p); } /// Test whether part is a sub-object of object template<class Object, class Part> bool is_within_object(Object& object, Part& part) { auto first = to_address(std::addressof(object)), last = first + sizeof(Object); auto p = to_address(std::addressof(part)); return (first <= p) and (p < last); } struct X { int a = 0; int& get_a() { return a; } int& get_b() { return b; } private: int
  • 小于空指针的比较(less than comparison for void pointers)
    问题 我想比较两个这样的空指针: void foo(void* p1, void* p2) { if (p1 < p2) { void *tmp = p1; p1 = p2; p2 = tmp; } // do something with p1 and p2. } 根据标准,这正确吗? 我的意思是比较void指针是一种定义明确的行为吗? 如果有人可以指出该文档的C标准,我将不胜感激。 回答1 正如Drew McGowen在评论中指出的那样,但我将在此处发布报价: 6.5.8关系运算符 5比较两个指针时,结果取决于所指向对象在地址空间中的相对位置。 如果两个指向对象类型的指针都指向同一对象,或者都指向一个指向同一数组对象的最后一个元素的指针,则它们将比较equal 。 如果所指向的对象是同一聚合对象的成员,则指向稍后声明的结构成员的指针大于指向早于该结构声明的成员的指针,指向具有较大下标值的数组元素的指针大于指向同一数组的元素的指针下标值较低。 指向同一个联合对象的成员的所有指针都比较等于。 如果表达式P指向数组对象的元素,而表达式Q指向同一数组对象的最后一个元素,则指针表达式Q + 1比较大于P。在所有其他情况下,该行为是undefined 。 这是来自C11标准的。 C99是相同的。 从C++11 ,它或多或少都一样。 关于指针转换的一些调整,如果需要,我可以将其全部粘贴。
  • C / C ++中的原始指针和函数指针支持哪些操作?(What are the operations supported by raw pointer and function pointer in C/C++?)
    问题 函数指针支持的所有操作与原始指针有什么不同? 原始指针是否支持>,<,<=,> =运算符,如果有什么用? 回答1 对于函数指针和对象指针,它们都可以编译,但只能保证其结果对于同一完整对象的子对象的地址是一致的(您可以比较一个类或数组的两个成员的地址),并且如果比较一个函数或反对自己。 使用std::less<> , std::greater<>等将适用于任何指针类型,并且将给出一致的结果,即使未指定各个内置运算符的结果也是如此: void f() { } void g() { } int main() { int a, b; ///// not guaranteed to pass assert((&a < &b) == (&a < &b)); ///// guaranteed to pass std::less<int*> lss1; assert(lss1(&a, &b) == lss1(&a, &b)); // note: we don't know whether lss1(&a, &b) is true or false. // But it's either always true or always false. ////// guaranteed to pass int c[2]; assert((&c[0] < &c[1]) == (&c[0] < &c[1
  • == 和 C++ 重载运算符的区别(C++ overloading operators difference between == and <)
    问题 有人能解释一下重载==和<之间的区别吗? 例如,如果我使用地图: map<Type, int> a(); friend bool operator<(const Type& lhs, const Type& rhs); friend bool operator==(const Type& lhs, const Type& rhs); 当我调用时,我实现了两个运算符: a.find(value); ==的操作符函数正在被调用? 我觉得不是。 我调试并看到<被调用,但为什么呢? <的运算符函数的行为应该是什么? 我来自 Java,其中调用方法equals并且很容易理解行为。 谢谢。 回答1 operator==重载==运算符(没有其他); operator<重载<运算符(没有其他)。 std::map被定义为默认使用std::less (并且只有std::less ),并且std::less被定义为默认使用< 。 但是,总的来说,我建议不要重载operator<除非有序比较对您的类有意义,在这种情况下,您应该以连贯的方式重载所有六个比较运算符。 否则,您可以将比较函数类型指定为std::map的附加模板参数; 比较功能对象应该定义严格的弱排序关系。 如果该类型被设计为用作键,但排序仍然是完全任意的,您可能会专门化std::less 。 至于Java,没有运算符重载,显然不能使用<
  • IEEE 浮点数是否为 std::map 和 std::set 的有效键类型?(Are IEEE floats valid key types for std::map and std::set?)
    问题 背景 关联容器(例如 std::map)的键类型上的比较器的要求是它对键类型的元素强加了严格的弱顺序。 对于给定的比较器comp(x, y)我们定义equiv(x, y) = !comp(x, y) && !comp(y, x) 。 comp(x, y)是严格弱阶的要求是 不可反射性( !comp(x, x)对所有x ) 排序的传递性(如果comp(a, b)和comp(b, c)然后comp(a, c) )。 等价的传递性(如果equiv(a, b)和equiv(b, c)那么equiv(a, c) ) std::less<float> (默认比较器)使用operator< ,由于NaN ,它不会创建严格的弱顺序。 因为x < NaN和NaN < x是所有假x , NaN是相当于该比较下的所有浮筒,该场所条件#3: equiv(1.0, NaN)和equiv(NaN, 2.0)但不equiv(1.0, 2.0) 。 对于除 NaN 之外的 IEEE 浮点数,它是一个严格的弱顺序(其中每个数字都有自己的等价类,除了0和-0 )。 问题 这是否意味着由于上述问题,C++ 标准不允许使用 IEEE 浮点数(和(长)双精度数)作为关联容器中的键类型,即使我确保 NaN 永远不会被插入到容器中? 我不太确定标准中的“ Key元素”措辞—
  • 如何比较指针?(How to compare pointers?)
    问题 假设我有2个指针: int *a = something; int *b = something; 如果我想比较它们并查看它们是否指向同一位置,则(a == b)是否有效? 回答1 是的,这就是原始指针相等性的定义:它们都指向相同的位置(或者是指针别名); 通常在运行以C ++编码并由某些操作系统管理的应用程序的进程的虚拟地址空间中(但是C ++也可以用于通过具有Harward架构的微控制器对嵌入式设备进行编程:在此类微控制器上,禁止进行指针强制转换,并且没有意义-因为只读数据可以放在代码ROM中) 对于C ++,请阅读一本不错的C ++编程书,请访问此C ++参考网站,阅读您的C ++编译器(也许是GCC或Clang)的文档,并考虑使用智能指针进行编码。 也许还要阅读一些C ++标准草案,例如n4713或从您的ISO代表处购买官方标准。 在管理通过动态分配获得的指针和内存区域(例如::operator new )时,垃圾回收的概念和术语也很重要,因此请阅读GC手册。 有关Linux计算机上的指针,另请参见此。 回答2 对于一点事实,这是规范中的相关文字 等于运算符(==,!=) 可以将指向相同类型对象的指针与“直观”预期结果进行相等性比较: 从C ++ 11标准的5.10节开始: 可以比较相同类型的指针(在指针转换之后)是否相等。 当且仅当两个指针都为null
  • 键的 std::map 要求(设计决策)(std::map Requirements for Keys (Design Decision))
    问题 当我创建一个std::map<my_data_type, mapped_value> ,C++ 对我的期望是my_data_type有它自己的operator< 。 struct my_data_type { my_data_type(int i) : my_i(i) { } bool operator<(const my_data_type& other) const { return my_i < other.my_i; } int my_i; }; 原因是您可以从operator<派生operator>和operator== 。 b < a意味着a > b ,所以有operator> 。 !(a < b) && !(b < a)表示a既不小于b也不大于它,因此它们必须相等。 问题是:为什么 C++ 设计者不要求显式定义operator== ? 显然, operator==对于std::map::find()和从std::map删除重复项是不可避免的。 为什么要实现 5 个操作并调用一个方法两次才能不强迫我显式实现operator== ? 回答1 operator==对于std::map::find()是不可避免的 这是你大错特错的地方。 map根本不使用operator== ,它不是“不可避免的”。 如果!(x < y) && !(y < x) ,就映射而¨
  • 为什么要使用std :: less作为默认函子来比较std :: map和std :: set中的键?(Why use std::less as the default functor to compare keys in std::map and std::set?)
    问题 我想知道为什么std::map和std::set使用std::less作为默认函子来比较键。 为什么不使用与strcmp类似的函子? 就像是: template <typename T> struct compare { // Return less than 0 if lhs < rhs // Return 0 if lhs == rhs // Return greater than 0 if lhs > rhs int operator()(T const& lhs, T const& rhs) { return (lhs-rhs); } } 假设map有两个对象,分别是键key1和key2 。 现在,我们要插入另一个键为key3对象。 使用std::less , insert函数需要首先使用key1和key3调用std::less::operator() 。 假设std::less::operator()(key1, key3)返回false。 它必须在切换了键std::less::operator()(key3, key1) std::less::operator()再次调用std::less::operator() ,以确定key1等于key3还是key3大于key1 。 有两次调用std::less::operator()来确定第一个调用是否返回false。
  • 运算符 < 和 > 如何处理指针?(How do the operators < and > work with pointers?)
    问题 只是为了好玩,我有一个std::list的const char* ,每个元素都指向一个以空字符结尾的文本字符串,并在其上运行一个std::list::sort() 。 碰巧的是,它有点(没有双关语意)没有对字符串进行排序。 考虑到它正在处理指针,这是有道理的。 根据std::list::sort()的文档,它(默认情况下)在元素之间使用operator <进行比较。 暂时忘记列表,我的实际问题是:这些 (>, <, >=, <=) 运算符如何处理 C++ 和 C 中的指针? 他们只是比较实际的内存地址吗? char* p1 = (char*) 0xDAB0BC47; char* p2 = (char*) 0xBABEC475; 例如,在 32 位小端系统上, p1 > p2因为0xDAB0BC47 > 0xBABEC475 ? 测试似乎证实了这一点,但我认为最好将它放在 StackOverflow 上以供将来参考。 C 和 C++ 都对指针做了一些奇怪的事情,所以你永远不会真正知道...... 回答1 在 C++ 中,您不能仅使用关系运算符比较任何指针。 您只能比较指向同一数组中元素的两个指针或指向同一对象成员的两个指针。 (当然,您也可以将指针与其自身进行比较。) 但是,您可以使用std::less和其他关系比较函数对象来比较任意两个指针。 结果是实现定义的
  • 通用的less <>用于C ++标准中的指针(Universal less<> for pointers in C++ standard)
    问题 很多时候,我需要一组指针。 每次发生这种情况时,我最终都会为指针类型编写一个less <>实现-将两个指针转换为size_t并比较结果。 我的问题是-标准中是否可用? 我找不到那样的东西。 似乎足够普通了... 更新:似乎即将到来的标准通过为指针类型提供了less <>并包括了unordered_set来解决了所有问题。 几年后,这个问题将成为现实。 同时,当前标准对此没有“合法”解决方案,但是size_t强制转换有效。 更新更新:好吧,我会被吓坏了! 不只 std::map<void *, int, std::less<void*> > myMap; 可行,但即使 std::map<void *, int > myMap; 也一样 那是在gcc 3.4.1中。 我一直在做所有的这些演员表,而litb是完全正确的。 他引用的章节编号在当前标准中也完全相同。 欢呼! 回答1 使用比较函数对象less , greater等可以比较两个指针。否则,使用毯子operator< etc,仅当指针指向同一数组对象的元素或指向末尾的元素时才可以进行比较。 否则,结果不确定。 C ++ 03中的20.3.3/8 为模板greater , less , greater_equal和less_equal ,对于任何指针类型的特化得到总共顺序,即使内置的运算符< , > , <= >=没有。
  • 什么是透明比较器?(What are transparent comparators?)
    问题 在C ++ 14中,关联容器似乎已从C ++ 11进行了更改– [associative.reqmts] / 13说: 除非存在Compare::is_transparent类型,否则成员函数模板find , count , lower_bound , upper_bound和equal_range不应参与重载解析。 使比较器“透明”的目的是什么? C ++ 14还提供了如下库模板: template <class T = void> struct less { constexpr bool operator()(const T& x, const T& y) const; typedef T first_argument_type; typedef T second_argument_type; typedef bool result_type; }; template <> struct less<void> { template <class T, class U> auto operator()(T&& t, U&& u) const -> decltype(std::forward<T>(t) < std::forward<U>(u)); typedef *unspecified* is_transparent; }; 因此,例如, std::set<T, std
  • 将指针转换为整数是否定义了指针的总顺序?(Does casting pointers to integers define a total order on pointers?)
    问题 (与我之前的问题有关) 在 QT 中,QMap 文档说: QMap 的键类型必须提供operator<()指定总顺序。 然而,在qmap.h ,他们似乎使用类似于std::less东西来比较指针: /* QMap uses qMapLessThanKey() to compare keys. The default implementation uses operator<(). For pointer types, qMapLessThanKey() casts the pointers to integers before it compares them, because operator<() is undefined on pointers that come from different memory blocks. (In practice, this is only a problem when running a program such as BoundsChecker.) */ template <class Key> inline bool qMapLessThanKey(const Key &key1, const Key &key2) { return key1 < key2; } template <class Ptr> inline bool
  • 模板的专业化不同名称空间中的struct std :: less'(Specialization of 'template<class _Tp> struct std::less' in different namespace)
    问题 我专门针对数据类型使用“较少”(谓词)。 代码如下: template<> struct std::less<DateTimeKey> { bool operator()(const DateTimeKey& k1, const DateTimeKey& k2) const { // Some code ... } } 编译时(在Ubuntu 9.10上为g ++ 4.4.1),出现错误: 不同名称空间中的'template struct std :: less'的特化 我进行了一些研究,发现有一个“解决方法”,其中涉及将专业化包装在std名称空间中-即,将代码更改为: namespace std { template<> struct less<DateTimeKey> { bool operator()(const DateTimeKey& k1, const DateTimeKey& k2) const { // Some code ... } } } 实际上,这会关闭编译器。 但是,该解决方案来自5岁以上的工作人员(“伟大”的Victor Bazarof也不例外)。 此修复程序仍然可行,还是有更好的解决方案,还是“旧方法”仍然有效? 回答1 仍然是这样做的方法。 不幸的是,您无法像在类中那样在名称空间中声明或定义函数:您需要将它们实际包装在名称空间块中。 回答2
  • 在“for”循环中以 1 递增时,是否存在使用 > (<) 而不是 != 的技术原因?(Is there a technical reason to use > (<) instead of != when incrementing by 1 in a 'for' loop?)
    问题 我几乎从未见过这样的for循环: for (int i = 0; 5 != i; ++i) {} 在for循环中以 1 递增时,是否存在使用>或<而不是!=的技术原因? 或者这更像是一种约定? 回答1 while (time != 6:30pm) { Work(); } 现在是下午 6 点 31 分……该死,现在我下一次回家的机会是明天! :) 这表明更强的限制可以减轻风险,并且可能更直观地理解。 回答2 没有技术原因。 但是可以降低风险、可维护性和更好地理解代码。 <或>是比!=更强的限制,并且在大多数情况下实现完全相同的目的(我什至会在所有实际情况下说)。 这里有重复的问题; 和一个有趣的答案。 回答3 是的,这是有原因的。 如果你像这样写一个(基于普通旧索引的)for循环 for (int i = a; i < b; ++i){} 然后它对a和b任何值都按预期工作(即,当a > b时零迭代而不是无限,如果您使用i == b; )。 另一方面,对于迭代器,你会写 for (auto it = begin; it != end; ++it) 因为任何迭代器都应该实现operator!= ,但不是每个迭代器都可以提供operator< 。 也是基于范围的 for 循环 for (auto e : v) 不仅仅是花哨的糖,而且它们显着减少了编写错误代码的机会。 回答4
  • 为什么std :: function不等于相等?(Why is std::function not equality comparable?)
    问题 这个问题也适用于boost::function和std::tr1::function 。 std::function不等于可比性: #include <functional> void foo() { } int main() { std::function<void()> f(foo), g(foo); bool are_equal(f == g); // Error: f and g are not equality comparable } 在C ++ 11中,不存在operator==和operator!=重载。 在早期的C ++ 11草案中,重载被声明为已删除,并带有注释(N3092§20.8.14.2): // deleted overloads close possible hole in the type system 它没有说“类型系统中可能的孔”是什么。 在TR1和Boost中,已声明但未定义重载。 TR1规范注释(N1836§3.7.2.6): 这些成员函数应保持未定义状态。 [注意:类似布尔的转换打开了一个漏洞,可以通过==或!=比较两个函数实例。 这些未定义的void运算符弥补了漏洞并确保了编译时错误。 —尾注] 我对“漏洞”的理解是,如果我们具有bool转换函数,则该转换可用于相等比较(和其他情况下): struct S { operator
  • 原始指针查找的unique_ptrs集(Raw pointer lookup for sets of unique_ptrs)
    问题 我经常发现自己想写这样的代码: class MyClass { public: void addObject(std::unique_ptr<Object>&& newObject); void removeObject(const Object* target); private: std::set<std::unique_ptr<Object>> objects; }; 但是,很多std :: set接口对于std :: unique_ptrs都是无用的,因为查找函数需要std :: unique_ptr参数(我显然没有这些参数,因为它们归集合本身所有)。 我可以想到两个主要的解决方案。 创建一个临时的unique_ptr进行查找。 例如,上面的removeObject()可以像这样实现: void MyClass::removeObject(const Object* target) { std::unique_ptr<Object> targetSmartPtr(target); objects.erase(targetSmartPtr); targetSmartPtr.release(); } 将集合替换为指向unique_ptrs的原始指针的映射。 // ... std::map<const Object*, std::unique_ptr<Object>>
  • 检查指针是否指向数组内(checking if pointer points within an array)
    问题 我可以检查给定的指针是否指向数组中的对象,由其边界指定吗? template <typename T> bool points_within_array(T* p, T* begin, T* end) { return begin <= p && p < end; } 或者如果p指向数组边界之外,指针比较是否会调用未定义的行为? 在这种情况下,我该如何解决问题? 它适用于空指针吗? 还是无法解决? 回答1 尽管比较仅对数组内的指针和“越过末尾”有效,但使用以指针为键的 set 或 map 是有效的,它使用std::less<T*> 早在 1996 年,在 comp.std.c++ 上就有过关于这种方式的大讨论 回答2 直接来自 MSDN 文档: 不能比较不同类型的两个指针,除非: 一种类型是从另一种类型派生的类类型。 至少有一个指针被显式转换(强制转换)为类型 void *。 (另一个指针被隐式转换为类型 void * 以进行转换。) 所以一个void*可以与其他任何东西进行比较(包括另一个void* )。 但是这种比较会产生有意义的结果吗? 如果两个指针指向同一个数组的元素或指向数组末尾之外的元素,则指向具有较高下标的对象的指针比较高。 只有当指针指向同一数组中的对象或指向数组末尾后的位置时,才能保证指针的比较有效。 好像没有。 如果您还不知道您正在比较数组内的项目