嗨,我确定这一定是一个常见的问题,但是当我搜索它时,我找不到答案。我的问题主要涉及两个方面。我想比较他们的地址,并确定一个是否比另一个大。我希望在比较期间所有地址都是无符号的。这是真的,它在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);
谢谢大家!
答案 0 :(得分:24)
指针比较无法签名或无符号。指针不是整数。
C语言(以及C ++)仅为指向同一聚合(结构或数组)的指针定义相对指针比较。排序很自然:指向数组中索引较小的元素的指针较小。指向先前声明的结构成员的指针较小。就是这样。
你不能合法地比较C / C ++中的任意指针。这种比较的结果没有定义。如果您有兴趣比较存储在指针中的地址的数值,则您有责任首先手动将指针转换为整数值。在这种情况下,您必须决定是使用有符号还是无符号整数类型(intptr_t
或uintptr_t
)。根据您选择的类型,比较将是“签名”或“未签名”。
答案 1 :(得分:8)
整数到指针的转换是完全实现定义的,因此它取决于您使用的实现。
也就是说,只允许关联比较指向同一对象部分的指针(基本上,指向相同结构的子对象或同一数组的元素)。不允许将两个指针与任意完全无关的对象进行比较。
答案 2 :(得分:4)
从草案C ++标准5.9:
如果同一类型的两个指针
p
和q
指向不同的对象 不是同一对象的成员或同一数组的元素 或者对于不同的函数,或者如果只有其中一个为null,则为结果p<q
,p>q
,p<=q
和p>=q
未指明。
因此,如果您将数字转换为指针并进行比较,C ++会为您提供未指定的结果。如果您获取可以有效比较的元素的地址,则比较操作的结果将独立于指针类型的signed-ness指定。
注意未指定的不是未定义:很可能将指针与同一类型的不同对象的指针进行比较,这些对象不在同一个结构或数组中,你可以期望一些自我一致的结果(否则就不可能在树中使用这样的指针作为键,或者对vector
这样的指针进行排序,二进制搜索向量等,其中需要一致的直观整体<
排序。
请注意,在非常古老的C ++标准中,行为是 undefined - 就像James McNellis WG14/N1124 draft下的2005 answer andrewdski链接一样 -
答案 3 :(得分:1)
为补充其他答案,指向不同对象的指针之间的比较取决于标准。
在C99(ISO / IEC 9899:1999(E))中,第6.5.8节:
5 [...]在所有其他情况下,该行为是未定义。
在C ++ 03(ISO / IEC 14882:2003(E))中,第5.9节:
-其他指针比较为未指定。
答案 4 :(得分:0)
我知道这里的几个答案说你不能比较指针,除非它们指向相同的结构,但那是一个红色的鲱鱼,我会试着解释原因。您的一个指针指向数组的开头,另一个指向结尾,因此它们指向相同的结构。语言律师可以说,如果您的第三个指针指向对象之外,则比较未定义,因此对于所有x >= array.start
,true
可能是x
。但这不是问题,因为在比较时,C ++无法知道数组是否未嵌入更大的结构中。此外,如果你的地址空间是线性的,就像现在一样,你的指针比较将被实现为(un)有符号整数比较,因为任何其他实现都会变慢。即使在段和偏移的时间,(远)指针比较也是通过首先规范化指针然后将它们作为整数进行比较来实现的。
这一切归结为如此,如果你的编译器没问题,比较指针而不用担心标志应该工作,如果你关心的是指针指向数组,因为编译器应该使签名或无符号指针取决于C ++对象可能跨越的两个边界中的哪一个。
不同的平台在这个问题上表现不同,这就是为什么C ++必须将它留给平台。甚至有一些平台,其中0和80..00h附近的地址都不可映射或在进程启动时已经采用。在这种情况下,只要你保持一致就没关系。
有时这会导致兼容性问题。例如,Win32指针是无符号的。现在,它曾经是4GB地址空间的情况,只有下半部分(更确切地说是10000h ... 7FFFFFFFh,因为NULL指针分配分区)可供应用程序使用;高地址仅供内核使用。这导致一些人将地址放在有符号变量中,并且他们的程序将继续工作,因为高位始终为0.但随后来了/3GB
开关,这使得应用程序几乎可以使用3 GB(更确切地说是10000h ... BFFFFFFFh)并且应用程序会崩溃或表现不正常。
您明确声明您的程序将仅使用Windows,它使用无符号指针。但是,也许您将来会改变主意,使用intptr_t
或uintptr_t
会降低可移植性。我也想知道你是否应该这样做...如果你索引到一个数组,那么比较索引可能更安全。例如,假设您在1500000h ... 41500000h处有1 GB阵列,由16,384个元素组成,每个64 kB。假设您不小心查找了80,000指数 - 显然超出了范围。指针计算将产生39D00000h,因此指针检查将允许它,即使它不应该。