我是C ++的菜鸟,我正在喋喋不休地指点。
int
可以表示-2147483647到2147483647个值,因此总值为4294967296。
这需要32bit
(2 ^ 32),因此4 byte
。
我看到如果我从ptr+1
“指针”执行ptr
(指针运算)到int,它会正确移动4个内存地址(4个字节)。
但这些“4字节”都用于表示4294967296值。
在哪里存储定义“指向int的指针”类型的数据?我猜指针本身应该知道它指向的数据类型,即它是指针。这些信息存储在哪里?除了指向数据的地址?如果我“打印”指针,我只得到地址,而不是其他信息......
答案 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
可以表示愤怒-32767
到32767
之外的值。而且现实世界的编译器只支持16位int
。允许编译器支持更大的范围,但不是必需的。
要回答您的问题,请填写
表格int *x;
告诉编译器x
是指向int
的指针。编译器本身是用知识(硬编码或配置选项,取决于编译器的实现方式)实现的,关于所有本机类型(如int
)的大小 - 并且还实现了产生该值在任何使用sizeof
表达式的代码中(如sizeof(int)
)。因此编译器可以实现指针算法以适应。
编译器 - 因为它已经解析并解释了你的代码 - 也知道每个值和变量的类型 - 包括指针和int
s。
打印是另一个故事 - 打印指针会在没有类型信息的情况下在内存中打印地址,除非您编写代码以显式输出类型信息。
答案 2 :(得分:0)
编译器知道目标处理器体系结构上int
的大小(事实上,所有已定义类型的大小 - 甚至是编译器用户定义的大小)。
编译器决定在何处存储已编译程序的指针算术运算的增量大小。通常,它可以嵌入到指令流中。