C 指针如何知道项目的基本大小?
如“”中所述,我有一个后续问题 指针如何知道它所指向的数据的基本大小?指针是否存储基础类型的大小以便知道如何递增 我希望下面的代码将指针向前移动一个字节:C 指针如何知道项目的基本大小?,c,pointers,C,Pointers,如“”中所述,我有一个后续问题 指针如何知道它所指向的数据的基本大小?指针是否存储基础类型的大小以便知道如何递增 我希望下面的代码将指针向前移动一个字节: int intarr[] = { ... }; int *intptr = intarr; intptr = intptr + 1; printf("intarr[1] = %d\n", *intptr); 根据链接站点上公认的答案,指针按字节递增,而不是按底层的sizeof递增,指向的元素将导致大量的歇斯底里、混乱和混乱 虽然我知道这可能
int intarr[] = { ... };
int *intptr = intarr;
intptr = intptr + 1;
printf("intarr[1] = %d\n", *intptr);
根据链接站点上公认的答案,指针按字节递增,而不是按底层的sizeof
递增,指向的元素将导致大量的歇斯底里、混乱和混乱
虽然我知道这可能是不可避免的结果,但我仍然不明白指针在这方面是如何工作的。我不能声明一个指向某个struct[]
类型数组的void
指针吗?如果我声明了,那么void
指针如何知道按sizeof(struct mytype)
递增
编辑:我相信我已经解决了我遇到的大部分困难,但我还没有在代码中演示它 请看这里:
#包括
int main(int argc,char*argv[])
{
int intarr[]={0,5,10};
int*intptr=intarr;
//获取指针指向的值
printf(“intptr(%p):%d\n”、intptr、*intptr);
printf(“intptr(%p):%d\n”,intptr+1,*(intptr+1));
printf(“intptr(%p):%d\n”,intptr+2,*(intptr+2));
//指针值之间的差异应与sizeof(int)相同
printf(“intptr[0]:%p | intptr[1]:%p |差异:%d |应为:%d”,
intptr,intptr+1,(intptr+1)-intptr,sizeof(int));
返回0;
}
它在类型声明中p1
知道类型的大小,因为它是sizeof(*p1)
或sizeof(int)
<代码>p2不知道,因为未定义sizeof(void)
int *p1;
void *p2;
p1++; // OK
p2++; // Not defined behavior in C
当您将指针初始化为int*时,编译器知道它是一个int指针,并且每个跃点都应该符合sizeof(int)的大小 关于你的虚空问题,如果你做了以下事情:
int a[4] = {0,1,2,3}
void *b = a;
int c = a[1]; //a will point to the 1 so c will be 1
int d = b[1]; //it depends on the compiler where is b going to end
//and which value will c take, some compilers may not accept it
这就是函数需要一个void*作为参数的原因,比如fwrite()要求结构的大小和数组的大小,这是一个粗略的答案,但值得注意的是,在机器级别上,数据类型并不存在,正如我们在C中所知道的那样。我们可能有算术指令,对存储在某个通用寄存器中的整数进行运算,例如,但没有存储任何东西来标识某个寄存器的内容实际上是一个
int
。机器看到的只是各种类型内存中的一堆位和字节
因此,您甚至可能想知道,编译器是如何做到这一点的:
intz=x+y代码>
如果在程序运行时没有存储任何内容来识别存储x
和y
和z
内容的内存区域是int
,那么它怎么知道在这里进行整数加法呢
简而言之,机器不知道程序是否在运行。然而,当它生成用于运行程序的指令时,它就有了这些信息
指针也是这样:
int intarr[] = { ... };
int *intptr = intarr;
在这里执行类似于intptr+1
的操作可以将指针地址增加sizeof(int)
。编译器知道如何根据程序员在此C代码中提供的信息执行此操作。如果您这样做:
int intarr[] = { ... };
void *voidptr = intarr;
。。。然后尝试在voidptr
上执行任何算术都会导致错误,因为我们没有提供编译器知道要生成什么机器指令所需的信息
我不能声明一个指向某个struct[]类型数组的空指针吗
我这样做了,void指针怎么知道递增
sizeof(struct mytype)
不可能。void指针将等同于编译时信息的丢失,这将阻止编译器生成适当的指令。如果您不提供信息,编译器就不知道如何进行指针运算。这就是为什么接受像memcpy
这样的空指针的函数需要指定字节大小的原因。指针对象内容不提供此类信息,只有程序员可以提供,因为此类信息不会存储在程序运行时使用的内存中。在您的示例中:
- sizeof(指针)是4个字节
- sizeof(int)是4个字节
在你的节目里
Output:
intptr(0xffcbf5dc): 0
intptr(0xffcbf5e0): 5
intptr(0xffcbf5e4): 10
intptr[0]: 0xffcbf5dc | intptr[1]: 0xffcbf5e0 | difference: 1 | expected: 4
如果您尝试:0xffcbf5e0-0xffcbf5dc=4(十六进制sub),这是sizeof(int)
- 关于使用void*:您可以使用void*
- 关于你的结构:你可以制作(你的结构)的大小
指针是否存储基础类型的大小以便知道如何递增
这个问题表明,需要在运行时将类型信息保存在对象中,以便正确决定如何对类型执行正确的操作。那不是真的。类型信息成为代码的一部分
如果我们在混合中添加第三种类型,可能更容易理解:浮点
考虑以下示例程序:
int a,b,c;
float x,y,z;
void f(void)
{
c = a+b*3;
z = x+y*3;
}
(我要求您首先考虑一下float
与int
的情况,不是因为它更简单,而是因为它更复杂。额外的复杂性使您无法选择诱人但错误的捷径。)
编译器必须将f
翻译成执行两种不同加法和乘法的汇编代码。虽然相同的运算符(+
和*
)在C代码中出现两次,但汇编代码看起来并不那么对称。前半部分将使用处理器的整数寄存器、整数加法指令和整数乘法指令,后半部分将使用浮点寄存器、浮点加法和浮点乘法指令
int a,b,c;
float x,y,z;
void f(void)
{
c = a+b*3;
z = x+y*3;
}