【问题标题】:Address location and value at address location in CC中的地址位置和地址位置的值
【发布时间】:2019-09-25 05:44:42
【问题描述】:
int PileInts[1024];
char *Pile = (char *)PileInts;

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

【问题讨论】:

  • 创建一个名为 *Pile 的字符,它给出 PileInts 处的地址值 不是字符,而是指向字符的指针。这是(不是真的)int 上的指针到char 上的指针的转换。
  • @user3365922 -- 嗯,你是什么意思(不是真的)?这正是它的作用。在访问时PileInts 被转换为指向第一个元素的指针,它是对char * 的强制转换和分配给Pile 的地址(不违反C 标准6.5(p6),因为它在6.5(p7) 中是允许的. 见C11 Standard - 6.5 Expressions)
  • @DavidC.Rankin 我的意思是int* 和int[N] 并不完全相同,不是吗?
  • 好吧,明白了,一开始我有点困惑。所以int* 是一个指向 int 的指针,而[...] 则作为取消引用,使类型int。你是对的,所以如果p 是一个指针,那么p[N] 与*(p + N) 相同,即int 类型。

标签: c pointer-conversion


【解决方案1】:

线

int PileInts[1024];

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

线

char *Pile = (char *)PileInts;

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

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

【讨论】:

  • 我能用 Pile 做什么?我并不是很了解指针的用途。
  • @4386427:如果你能显示示例代码,打印地址以便 OP 可以知道 1 字节地址增量,那将是很好的
  • @kevinmarks (type is King!) 它控制指针运算。因此,假设您使用int *p = PileInts;,然后将指针p 前进一个(p = p + 1;),因为它键入的指针int、p + 1 在内存中前进了4 个字节到下一个int。通过转换为char *,Pile 的类型是指向char 的指针。因此,如果您推进Pile,例如(Pile = Pile + 1;),现在Pile 指向PileInt 中的下一个字节,而不是下一个int。
  • @Inian 添加了打印地址的示例
  • 非常感谢。我现在得到了一点。我还有另一个问题。我把这个数组组织成一个 64x64 的盒子,每个位置都有一个值。如何检查垂直方向某些行中的值是否相同?
【解决方案2】:

line 创建了一个名为*Pile 的字符,它给出了 PileInts 处地址的值

没有。它创建一个指向名为Pile 的字符char* 的指针,该指针指向int 数组中第一个int 中的最低字节-

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

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

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

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

  • 首先,每当试图访问原始数据值时,都应使用uint8_t*。 char 类型存在很大问题,因为它具有实现定义的符号性——它不应该用于除字符和字符串之外的任何其他内容。 Is char signed or unsigned by default?

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

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

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

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

标准中的相同段落继续:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-15
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    相关资源
    最近更新 更多