当前位置: 首页 > 知识库问答 >
问题:

C是否有与C++等价的STD::Less?

满言
2023-03-14

我最近回答了一个问题,关于当pq是指向不同对象/数组的指针时,在C中执行p 的未定义行为。这让我想到:在本例中,C++具有与 <相同的(未定义的)行为,但也提供了标准库模板 std::less,当指针可以比较时,它保证返回与 <相同的内容,当指针不能比较时,返回一些一致的顺序。

C是否提供了类似的功能,允许安全地比较任意指针(指向同一类型)?我试着浏览C11标准,但没有发现任何东西,但我在C方面的经验比在C++方面要小几个数量级,所以我很容易错过一些东西。


共有1个答案

伏默
2023-03-14

对于具有平面内存模型的实现(基本上是所有的),转换为UINTPTR_T就可以了。

(但是请参见在64位x86中指针比较应该是有符号的还是无符号的?以讨论是否应该将指针视为有符号的,包括在对象之外形成指针的问题,这在C中是UB。)

但是具有非平面内存模型的系统确实存在,考虑它们可以帮助解释当前的情况,比如C++对于<std::less有不同的规范。

但是,即使在C++std::less必须昂贵的系统上,<也不必昂贵。例如,假设一个“大”内存模型,其中一个对象适合于一个段,<可以只比较偏移量部分,甚至不必考虑段部分。(同一对象中的指针将具有相同的段,否则在C.C++17中它是UB,只改为“unspecified”,这可能仍然允许跳过规范化和只比较偏移量。)这是假设指向对象任何部分的所有指针始终使用相同的seg值,从不进行规范化。这就是ABI所要求的“大”内存模型,而不是“大”内存模型。(见评论中的讨论)。

(例如,这样的内存模型可能具有64KIB的最大对象大小,但最大总地址空间要大得多,可以容纳许多此类最大大小的对象。ISO C允许实现对对象大小的限制低于size_t可以表示的最大值(无符号)size_max。例如,即使在平面内存模型系统上,GNU C也将最大对象大小限制为ptrdiff_max,因此大小计算可以忽略符号溢出。)在评论中看到这个答案和讨论。

如果希望允许大于段的对象,则需要一个“巨大”的内存模型,该模型在执行p++循环数组时,或者在执行索引/指针算术时,必须担心指针的偏移量部分溢出。这会导致所有地方的代码都变慢,但可能意味着p 会碰巧适用于指向不同对象的指针,因为目标是“巨大”内存模型的实现通常会选择始终保持所有指针的规范化。看到什么是近的,远的和巨大的指针吗?-一些用于x86 real mode的real C编译器确实有一个选项来编译“HUGE”模型,其中所有指针都默认为“HUGE”,除非另有声明。

x86实模式分段并不是唯一可能的非平面内存模型,它只是一个有用的具体例子来说明C/C++实现是如何处理它的。在现实生活中,实现使用farnear指针的概念扩展了ISO C,允许程序员选择何时可以只存储/传递相对于某个公共数据段的16位偏移部分。

但是,一个纯ISO C实现必须在小内存模型(除了相同的64KIB中的代码以外的所有内存模型和16位指针)或大内存模型和大内存模型(所有指针都是32位的)之间进行选择。有些循环可以通过增加偏移量部分来优化,但是指针对象不能被优化得更小。

如果您知道任何给定实现的神奇操作是什么,您可以用纯C实现它。问题是不同的系统使用不同的寻址,并且细节不是由任何可移植宏参数化的。

您可以手动添加用于各种特定平台的代码,例如,默认情况下假设flat,或#ifdef检测x86实际模式,并将UINTPTR_T拆分为16位的两部分,用于seg-=off>>4;off&=0xf;然后将这些部分组合回一个32位数字。

 类似资料:
  • 问题内容: 是否有与C ++等效的Java Map keySet()? Java 方法返回“此映射中包含的键的设置视图”。 问题答案: 也许以下可能有用: 使用STL兼容序列(例如std :: vector,std :: deque或std :: list)的 make_key_set 函数的重载可以如下所示:

  • Java7引入了MethodHandle类,用于动态执行给定类的方法。据我所知,在JDK的Android端口上没有这样的东西。除了使用标准的反射类之外,是否有任何解决方法可以用来绕过这个问题?

  • 问题内容: Java具有格式字符串的概念,与其他语言的格式字符串非常相似。它用于诸如输出转换之类的JDK方法中。 我想知道在Java中是否有类似于C的输入转换方法? 问题答案: 看一下该站点,它解释了两种使用java中的控制台读取的方法,使用或使用System.in中的经典方法。 以下代码摘自引用的网站: - 问候。

  • 问题内容: 如何在Java中解码使用HttpServerUtility.UrlTokenEncode在C#中编码的字符串? 问题答案: 我尝试使用(ctor接受一个参数,说明编码/解码是否是url安全的),但事实证明它的实现方式与UrlTokenEncode / Decode不同。 我最终将C#实现迁移到Java:

  • 此示例代码是否在所有系统上导致两个相等的值?

  • 问题内容: 我是来自C / STL的相对较新的Java程序员,并且正在寻找具有以下特征的类(据我所了解,C std :: deque具有): O(1)在开头/结尾插入/移除的性能 按索引查找的O(1)性能 是可增长的集合(不需要固定的大小范围) 是否有与此等效的Java?我发现Java 1.6 [ArrayDeque]类具有插入/移除和可增长的特性,但是似乎没有按索引查找的方法,除非调用toArr