指针如何知道指向元素的结尾?

时间:2016-07-01 09:41:59

标签: c++ pointers memory-management

我是C ++的菜鸟,我正在喋喋不休地指点。

int可以表示-2147483647到2147483647个值,因此总值为4294967296。

这需要32bit(2 ^ 32),因此4 byte

我看到如果我从ptr+1“指针”执行ptr(指针运算)到int,它会正确移动4个内存地址(4个字节)。

但这些“4字节”都用于表示4294967296值。

在哪里存储定义“指向int的指针”类型的数据?我猜指针本身应该知道它指向的数据类型,即它是指针。这些信息存储在哪里?除了指向数据的地址?如果我“打印”指针,我只得到地址,而不是其他信息......

3 个答案:

答案 0 :(得分:2)

编译器具有可用的类型信息,以了解如何生成评估ptr + 1之类的内容所需的底层机器代码。在机器级别,它相当于说ptr + sizeof(*ptr)。所以,如果你有这样的代码:

int *ptr = // some address;
ptr++;

然后编译器(在x86上)将为ptr++发出类似的内容:

mov eax,dword ptr [ptr]  ; Load the pointer
add eax,4                ; Add 4 to the address as sizeof(*ptr) is 4
mov dword ptr [ptr],eax  ; Write the new value back

编译器具有类型信息这一事实意味着ptr + 1的评估是静态的,而不是动态的,并且当您获得通过指针传递给基类型的派生类型数组时会导致问题。举个例子:

struct Base
{
  int x;
}; 

struct Derived : Base
{
  int y;
};

void PrintAll(Base *p, int numberOfItems)
{
  while(numberOfItems--)
  {
    std::cout << p->x << std::endl;
    p++; // Oops!!!
  }
}

Derived data[10];
Derived *ptr = data;
PrintAll(ptr, 10);

标有“哎呀!!!”的行没有按预期工作。虽然ptr实际指向Derived类型的对象,但它实际上只会尝试将ptr移动到指向下一个Base而不是Derived所有编译器可用的编译时间(即静态)信息。这会导致未定义的行为。如果ptr实际指向了Base的数组,那么我们就可以了。这样的错误在编译时很难检测到,这就是为什么你最好使用像std::vector这样的容器来做这种事情。

答案 1 :(得分:2)

首先,C标准不要求int可以表示愤怒-3276732767之外的值。而且现实世界的编译器只支持16位int。允许编译器支持更大的范围,但不是必需的。

要回答您的问题,请填写

表格
int *x;

告诉编译器x是指向int的指针。编译器本身是用知识(硬编码或配置选项,取决于编译器的实现方式)实现的,关于所有本机类型(如int)的大小 - 并且还实现了产生该值在任何使用sizeof表达式的代码中(如sizeof(int))。因此编译器可以实现指针算法以适应。

编译器 - 因为它已经解析并解释了你的代码 - 也知道每个值和变量的类型 - 包括指针和int s。

打印是另一个故事 - 打印指针会在没有类型信息的情况下在内存中打印地址,除非您编写代码以显式输出类型信息。

答案 2 :(得分:0)

编译器知道目标处理器体系结构上int的大小(事实上,所有已定义类型的大小 - 甚至是编译器用户定义的大小)。

编译器决定在何处存储已编译程序的指针算术运算的增量大小。通常,它可以嵌入到指令流中。

相关问题