C中的指针比较是签名还是未签名?

嗨,我确定这一定是一个常见的问题,但是当我搜索它时,我找不到答案。 我的问题主要涉及两个方面。 我想比较他们的地址,并确定一个是否比另一个大。 我希望在比较期间所有地址都是无符号的。 这是真的,它在C89,C99和C ++之间有所不同吗? 当我用gcc编译时,比较是无符号的。

如果我有两个指针,我正在比较这样:

char *a = (char *) 0x80000000; //-2147483648 or 2147483648 ? char *b = (char *) 0x1; 

然后a更大。 这是否由标准保证?

编辑以更新我想要做的事情。 我有一种情况,我想确定如果有算术错误,它不会导致指针超出界限。 现在我有数组的起始地址和结束地址。 如果出现错误并且指针计算错误,并且在数组内存的有效地址之外,我想确保不会发生访问冲突。 我相信我可以通过比较另一个函数返回的可疑指针并确定它是否在数组的可接受范围内来防止这种情况。 负面和正面地址的问题与我是否可以进行比较有关,正如我在原始问题中所讨论的那样。

到目前为止,我很欣赏答案。 根据我的编辑,你会说我正在做的是gcc和msvc中未定义的行为吗? 这是一个仅在Microsoft Windows上运行的程序。

这是一个简单的例子:

 char letters[26]; char *do_not_read = &letters[26]; char *suspect = somefunction_i_dont_control(letters,26); if( (suspect >= letters) && (suspect < do_not_read) ) printf("%c", suspect); 

另一个编辑,在阅读AndreyT的回答后,似乎是正确的。 因此我会做这样的事情:

 char letters[26]; uintptr_t begin = letters; uintptr_t toofar = begin + sizeof(letters); char *suspect = somefunction_i_dont_control(letters,26); if( ((uintptr_t)suspect >= begin) && ((uintptr_t)suspect < toofar ) ) printf("%c", suspect); 

感谢大家!

指针比较无法签名或未签名。 指针不是整数。

C语言(以及C ++)仅为指向同一聚合(结构或数组)的指针定义指针比较。 排序很自然:指向数组中索引较小的元素的指针较小。 指向先前声明的结构成员的指针较小。 而已。

你不能合法地比较C / C ++中的任意指针。 这种比较的结果没有定义。 如果您有兴趣比较存储在指针中的地址的数值,则您有责任首先手动将指针转换为整数值。 在这种情况下,您必须决定是使用有符号还是无符号整数类型( intptr_tuintptr_t )。 根据您选择的类型,比较将是“签名”或“未签名”。

整数到指针的转换是完全实现定义的,因此它取决于您使用的实现。

也就是说,您只能通过关系比较指向同一对象部分的指针(基本上,指向相同结构的子对象或同一数组的元素)。 您不能比较两个指向任意,完全不相关的对象的指针。

从草案C ++标准5.9:

如果相同类型的两个指针pq指向不是同一对象的成员或同一数组的元素或不同函数的不同对象,或者如果只有其中一个为null,则pp>qp<=qp>=q未指定。

因此,如果您将数字转换为指针并进行比较,C ++会为您提供未指定的结果。 如果获取可以有效比较的元素的地址,则比较操作的结果将独立于指针类型的signed-ness指定。

注意未指定 未定义 :很可能将指针与同一类型中不在同一结构或数组中的不同对象进行比较,并且可以期望一些自洽的结果(否则就不可能使用这样的指针)作为树中的键,或者对这些指针的vector进行排序,二元搜索矢量等,其中需要一致的直观整体<排序。

请注意,在非常古老的C ++标准中,行为是未定义的 - 就像2005年WG14 / N1124草案和James McNellis的回答下的andrewdski链接一样 -

我知道这里的几个答案说你不能比较指针,除非它们指向相同的结构,但那是一个红色的鲱鱼,我会试着解释原因。 你的一个指针指向数组的开头,另一个指向结尾,因此它们指向相同的结构。 语言律师可以说,如果你的第三个指针指向对象之外,则比较是未定义的,因此对于所有xx >= array.start可能为true 。 但这不是问题,因为在比较时,C ++无法知道数组是否未嵌入更大的结构中。 此外,如果你的地址空间是线性的,就像现在一样,你的指针比较将被实现为(un)有符号整数比较,因为任何其他实现都会变慢。 即使在段和偏移的时间,(远)指针比较也是通过首先规范化指针然后将它们作为整数进行比较来实现的。

这一切归结为是,如果你的编译器没问题,比较指针而不用担心标志应该工作,如果你关心的只是指针指向数组,因为编译器应该使指针签名或无符号取决于C ++对象可能跨越的两个边界中的哪一个。

不同的平台在这个问题上表现不同,这就是为什么C ++必须将它留给平台。 甚至有一些平台,其中0和80..00h附近的地址都不可映射或已在​​进程启动时使用。 在这种情况下,只要你保持一致就没关系。

有时这会导致兼容性问题。 例如,Win32指针是无符号的。 现在,它曾经是4GB地址空间的情况,只有下半部分(更确切地说是10000h … 7FFFFFFFh,因为NULL指针分配分区)可供应用程序使用; 高地址仅供内核使用。 这导致一些人将地址放在有符号变量中,并且他们的程序将保持工作,因为高位始终为0.但随后来了/3GB开关,这使得应用程序几乎可以使用3 GB(更确切地说是10000h … BFFFFFFFh)和应用程序会崩溃或表现不正常。

您明确声明您的程序将仅使用Windows,它使用无符号指针。 但是,也许你将来会改变主意,使用intptr_tuintptr_t对于可移植性是不利的。 我也想知道你是否应该这样做…如果你索引到一个数组,那么比较索引可能更安全。 例如,假设您在1500000h … 41500000h处有1 GBarrays,由16,384个元素组成,每个元素64 kB。 假设您不小心查找了80,000指数 – 显然超出了范围。 指针计算将产生39D00000h,因此指针检查将允许它,即使它不应该。