这取自C,并以此为基础。 我们假设我们有一个32位指针
char* charPointer;
它指向内存中包含一些数据的某个位置。它知道这个指针的增量是1个字节,等等。 另一方面,
int* intPointer;
也指向内存中的某个位置,如果我们增加它,它知道如果我们加1则它应该增加4个字节。
问题是,我们如何能够使用这些指针来处理完整的32位可寻址空间(2 ^ 32) - 4千兆字节,如果显然它们中包含一些允许它们彼此分离的信息,例如char*
或int*
,因此这不会留下32个字节,但会少一些。
在输入这个问题时,我开始思考,也许它是所有的合成糖,真的是编译器?也许原始指针只是32位,它不关心类型?是这样的吗?
答案 0 :(得分:18)
您可能会对编译时间与运行时间感到困惑。
在编译期间,gcc
(或任何C编译器)知道指针的类型,特别是知道该指针变量指向的数据的类型。因此gcc
可以发出正确的机器代码。因此,int *
变量的增量(在具有32位int
的32位机器上)被转换为4(字节)的增量,而char*
变量的增量被转换增量为1。
在运行时,编译后的可执行文件(它不关心或需要gcc
)只处理机器指针,通常是字节地址(或某些单词的开头)。
类型(在 C 程序中)在运行时期间是未知的。
其他一些语言(Lisp,Python,Javascript,....)要求在运行时知道类型。在最近的C ++(但不是C)中,一些对象(具有虚函数的对象)可能有RTTI。
答案 1 :(得分:13)
确实是语法糖。请考虑以下代码片段:
int t[2];
int a = t[1];
第二行实际上是
的捷径int a = *(t + 1); // pointer addition
本身是
的捷径int a = *(int*)((char*)t + 1 * sizeof(int)); // integer addition
在编译器检查了类型后,它会删除强制类型转换器,并且只能处理地址,长度和整数。
答案 2 :(得分:3)
是。原始指针是32位数据(或16位或64位,具体取决于体系结构),并且不包含任何其他内容。它是int *
,char *
,struct sockaddr_in *
只是编译器的信息,知道在递增时实际添加的数字是什么,以及当你取消引用它时它将具有的类型。
答案 3 :(得分:3)
您的假设是正确的:要了解如何处理不同类型的指针,请尝试运行此程序:
int main()
{
char * pc = 0;
int * pi = 0;
printf("%p\n", pc + 1);
printf("%p\n", pi + 1);
return 0;
}
你会注意到,在char *中添加一个会使其数值增加1,而对int *执行相同操作会增加4(这是我机器上int的大小)。
答案 4 :(得分:2)
正如你最后所说的那样 - C中的类型只是一个编译时概念,告诉编译器如何为变量执行的各种操作生成代码。
最后,指针只是归结为它们指向的地址,一旦编译代码,语义信息就不再存在了。
答案 5 :(得分:1)
增加int *指针与增量char *不同,因为指针变量声明为int *。您可以将int *转换为char *,然后它将以1个字节递增。
所以,是的,这只是语法糖。它使某些类型的数组处理更容易,并使void *用户感到困惑。