int指针指向void指针指向char数组?

chy5wohz  于 2023-02-11  发布在  其他
关注(0)|答案(3)|浏览(143)

我在理解下面的代码时遇到困难:

char arr[] = {0,1,2,3};
void *vp;
int *ip;

vp = arr; 
ip = vp;

如果数组本身是char,int指针ip怎么可能指向arr的元素呢?据我所知,定义指针时,它必须与它所指向的数据类型相同,但为什么在这种情况下是可能的呢?

gojuced7

gojuced71#

如果数组本身是char,int指针ip怎么可能指向arr的元素呢?
这是不可能的。给出的代码是有效的,但效果是不会在ip中存储指向数组arr的任何元素的指针。* 根据定义 *,ip指向int,而arr的元素不是int,因此ip不会指向其中任何一个元素。
据我所知,在定义指针时,它必须与它所指向的数据类型相同,但为什么在这种情况下是可能的呢?
因为指针值不一定有效(对于它们的类型,甚至一般情况下)。给出的代码的结果不是ip指向char,而是试图引用它的值会产生 undefined behavior。在ip = NULL;之后也是如此,尽管计算*ip所产生的undefined behavior在这两种情况下可能不同。
你可以把它描述为ip不指向任何东西,尽管我想你会意识到这是一个不完整的描述,ip = vp的效果通常与ip = NULL的效果不同。
更广泛地说,必须理解指针是它们自己的值,与它们所指向的对象(如果有的话)不同,并且没有内在的联系。

ubby3x7f

ubby3x7f2#

此代码

char arr[] = {0,1,2,3};
void *vp;
int *ip;

vp = arr; 
ip = vp;

可以调用未定义的行为。
根据6.3.2.3指针,C11标准(草案)第7段(粗体):
指向一个对象类型的指针可以转换为指向另一个对象类型的指针。如果生成的指针与引用的类型没有正确对齐,则该行为未定义。
注意,指针的解引用不是必需的--仅仅创建一个未对齐的指针就调用了未定义的行为。
由于不能保证arrint值正确对齐,因此不能排除未定义的行为。
如果你真的解引用ip,并访问arr,就像它是一个int值一样,这将违反strict aliasing,而且永远是未定义的行为。

rqcrx0a6

rqcrx0a63#

这段代码做"指针双关"。它是一种将一种类型的二进制表示用作另一种类型的方法。
在C中,它违反了严格的定义规则,是未定义的行为。
在您的示例中(假设int为4个字节),char数组的内容将被解释为int值。

int main(void)
{
    char arr[] = {0,1,2,3};
    int *ip = (int *)arr;

    printf("%d - 0x%08x\n", *ip, *ip);

}

输出

50462976 - 0x03020100

十六进制值更容易解释,因为数字的两位数代表内存中的一个字节。正如您所看到的,与内存中的表示相比,数字是"反向的"。这是因为PC计算机是小端存储,最低有效字节首先存储。https://en.wikipedia.org/wiki/Endianness
要避免未定义的行为,应将数组复制到整数中

int main(void)
{
    char arr[] = {0,1,2,3};
    int ip;

    memcpy(&ip, arr, sizeof(ip));
    printf("%d - 0x%08x\n", ip, ip);
}

如果数组本身是char,int指针ip怎么可能指向arr的元素呢?
最后,任何对象(不管它的类型是什么)都只是存储在内存中的一堆字符(字节),你的指针指向内存中的某个位置。

相关问题