Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 指针如何知道项目的基本大小?_C_Pointers - Fatal编程技术网

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;
}