2015-03-13 114 views
4

我在写一些将虚拟地址映射到物理地址的代码。可以比较C中的指针和整数吗?

我沿着这些线路代码:

if (address > 0xFFFF) 
    Status = XST_FAILURE; // Out of range 
else if (address <= 0xCFFF || address >= 0xD400) { 
    // Write to OCM 
    Xil_Out8(OCM_HIGH64_BASEADDR + OCM_OFFSET + address, data); 
else { // (address >= 0xD000) 
    // Write to external CCA 
    Status = ext_mem_write(address, data); 

我得到一个编译器警告: comparison between pointer and integer [enabled by default]

我意识到,我比较了两种不同类型(指针和整数),但是这是一个问题?毕竟,比较指向一个整数的指针正是我想要做的。

定义指针常量来比较而不是整数会更清晰吗?

const int *UPPER_LIMIT = 0xFFFF; 
... 
if (address > UPPER_LIMIT){ 
    .... 
+3

最好将指针转换为整数,而不是将整数转换为指针。这是因为指针的比较运算符没有很好的定义,但是对于它们的整数。 – 2015-03-13 19:30:15

+2

指针通常是一个无符号整数,将其与有符号整数进行比较可能会由于转换而产生意外的结果。 – dtech 2015-03-13 19:31:05

+0

一旦您确信自己所做的工作,使用强制转换来击败编译器警告,而不是禁用警告。但只有这样;)。也许从@EugeneSh实施建议。将删除警告。 – 2015-03-13 19:34:05

回答

3

干净的方法是使用uintptr_t类型的常量,它被定义为一个无符号整数,可以在指针和整数之间唯一映射。

这应该由#include <stdint.h>定义。如果未定义,则表明您的编译器不遵循C标准,或者系统没有平坦的内存模型。

它旨在以“明显”的方式进行映射,即每个字节按升序排列一个整数。该标准并不能绝对保证,但作为实施问题的质量,很难看到其他事情发生。

实施例:

uintptr_t foo = 0xFFFF; 

void test(char *ptr) 
{ 
    if ((uintptr_t)ptr < foo) 
     // do something... 
} 

这是由C标准明确定义。您使用void *而不是uintptr_t的版本是未定义的行为,尽管如果您的编译器不太具有侵略性,它可能会工作。

+0

嗯。我试过这个,我仍然得到同样的警告。 – Spark 2015-03-16 20:48:03

+0

@Spark仔细检查你的代码,这段代码不会给出警告。也许警告来自你的代码的另一部分。 – 2015-03-16 21:04:51

+0

啊哈 - 我忘记了(uintptr_t)在指针上的投射。 – Spark 2015-03-17 13:18:38

2

这可能是为什么Linux内核使用unsigned long的地址(注意区别 - 指针指向的对象,而地址是在内存中的位置代表一个抽象的代码)。

这是从编译器的角度如何看起来:

  1. C标准没有定义如何比较int(算术型)字面0xFFFF和指针address - 见第6.5.8
  2. 所以,它必须以某种方式转换操作数。这两种转换的实现都定义为段落6.3.2.3的状态。这里有几个疯狂的决策,编译资格做:
    • 因为0xFFFF可能是int - 见6.4.4,它可能会强制将指针int,如果sizeof(int) < sizeof(void*),你将失去高字节。
    • 我能想象的要多疯狂的情况下,当0xFFFF被符号扩展至0xFFFFFFFF(不应该,但为什么不)

当然,没有(2)应该发生的,现代的编译器是聪明足够。但它可能会发生(我假设你正在编写嵌入的东西,它更可能发生),所以这就是编译器提出警告的原因。

这里是“疯狂的编译器的事情”一个实际的例子:在GCC 4.8优化开始治疗整数溢出为UB(未定义行为),省略说明假设程序员不希望整数溢出https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61569

我指的是N1570 - C11标准草案

+1

第2点是错误的;任何试图比较指针和整数的代码都是不合格的。程序员必须使用转换来选择一个选项。 – 2015-03-13 21:04:20

+0

@MattMcNabb,但如果程序员不这样做,编译器必须决定如何处理这种情况。所以第2点描述了潜在的克服。 – myaut 2015-03-13 21:13:28

-1

角色指针无符号整型,以避免警告:(unsigned)address - 在32或16位的地址空间的情况下。

+2

为此目的存在可选类型'uintptr_t';它保证足够大以容纳一个指针。 – 2015-03-13 21:03:33