2
int PileInts[1024];
char *Pile = (char *)PileInts;

这两行代码的作用是什么?我认为该char *Pile = (char *)PileInts;行创建了一个名为的字符,该字符*Pile给出了地址的值PileInts。我对吗?我能得到更深入的解释吗?

4

2 回答 2

3

线

int PileInts[1024];

创建一个由 1024 个整数组成的数组对象。可以使用变量名访问该对象PileInts

线

char *Pile = (char *)PileInts;

创建一个char 指针对象并使其指向数组对象的第一个 char。使用变量 name 访问 char 指针对象Pile

char 指针Pile可用于访问PileInts. 例子:

#include <stdio.h>

int main(void) {
    int PileInts[1024];
    char *Pile = (char *)PileInts;

    PileInts[0] = 1;
    PileInts[1] = 2;

    // Print the bytes/chars of the first two ints of PileInts
    for (unsigned i= 0; i < (2 * sizeof PileInts[0]); ++i)
    {
        printf("0x%02x\n", *Pile); // Print what Pile points to
        ++Pile;                    // Increment Pile so it points to the next byte/char
    }
    return 0;
}

可能的输出:

0x01
0x00
0x00
0x00
0x02
0x00
0x00
0x00

注意:由于不同的字节序和/或整数大小,输出可能因系统而异。

如果您想查看 的值Pile,即它指向的地址,您可以将代码更改为:

#include <stdio.h>

int main(void) {
    int PileInts[1024];
    char *Pile = (char *)PileInts;

    PileInts[0] = 1;
    PileInts[1] = 2;

    for (unsigned i= 0; i < (2 * sizeof PileInts[0]); ++i)
    {
        printf("Pile points to addresss %p where the value 0x%02x is stored\n", 
               (void*)Pile, *Pile);
        ++Pile;
    }
    return 0;
}

可能的输出:

Pile points to addresss 0x7ffe5860b8e0 where the value 0x01 is stored
Pile points to addresss 0x7ffe5860b8e1 where the value 0x00 is stored
Pile points to addresss 0x7ffe5860b8e2 where the value 0x00 is stored
Pile points to addresss 0x7ffe5860b8e3 where the value 0x00 is stored
Pile points to addresss 0x7ffe5860b8e4 where the value 0x02 is stored
Pile points to addresss 0x7ffe5860b8e5 where the value 0x00 is stored
Pile points to addresss 0x7ffe5860b8e6 where the value 0x00 is stored
Pile points to addresss 0x7ffe5860b8e7 where the value 0x00 is stored
于 2019-09-25T05:50:00.460 回答
1

行创建一个名为的字符,该字符*Pile给出 PileInts 处的地址值

不,它会创建一个指向char*名为的字符的指针,该指针指向数组中Pile第一个中的最低字节-intint

我能得到更深入的解释吗?

该代码提供了一个指针,可用于访问int数组中第一个字节的各个字节,然后从那里访问下一个相邻字节的各个字节int,直到数组末尾。

这是可能的,因为当在表达式中使用数组名称时,它“衰减”为指向该数组第一个元素的指针。PileInts当在数组中使用时,making等效于 type int*

转换 fromint*char*有效的,但有问题 C. 需要注意的一些事项:

  • 首先,uint8_t*应该在试图访问原始数据值时使用。该char类型有很大的问题,因为它具有实现定义的签名——它不应该用于除字符和字符串之外的任何其他内容。char 默认是有符号还是无符号?

  • 该指针将指向第一个的最低地址int。这对应于哪些字节是特定于 CPU 的,即取决于CPU 的字节序。使用按位移位运算符而不是指针将消除这种 CPU 依赖性,因此根据您要使用此指针执行的操作,它可能是也可能不是该任务的正确工具。

至于指针转换本身,按照 C17 6.3.2.3/7 没问题:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未正确对齐引用的类型,则行为未定义。否则,当再次转换回来时,结果将等于原始指针。

这意味着类似的东西(int*) ((char*)PileInts + 1)将是一个未定义的行为错误,因为int*将会错位。

标准中的同一段继续:

当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节。结果的连续增量,直到对象的大小,产生指向对象剩余字节的指针。

这是允许我们使用字符指针(或者最好是等效的)来迭代任何数据类型的规则uint8_t*。对于任何其他指针类型都不是这样,例如,我们可以使用 ashort*来做同样的事情,以为我们迭代了 16 位字。

还有另一条规则阻止我们使用任何其他指针类型,即调节编译器内部类型系统的规则以及不同指针如何成为彼此的别名。非正式地称为严格别名规则。此规则也仅对字符类型有例外。这意味着我们不能这样做:

int PileInts[1024];
char *Pile = (char *)PileInts;
short* sptr = (short*)Pile; // very questionable cast but not a bug yet
printf("%h", *sptr); // bug, data is accessed as wrong type, strict aliasing violation
于 2019-09-25T06:50:58.610 回答