【问题标题】:struct pointer manipulation结构指针操作
【发布时间】:2010-01-09 16:00:06
【问题描述】:

使用的代码

#include<stdio.h>

struct st
{
 char a;
 short c;
 int b;
};

struct st s1;
int main()
{
        printf("%p %p \n",(&s1.b)-1, &s1);
}

如果我打印&amp;s1.b 的地址,它会打印0x804a01c&amp;s1.b-2 打印0x804a018 如果我选择&amp;s1.b-1,为什么它会打印相同的地址0x804a01c

【问题讨论】:

  • 结构填充是实现定义的。
  • @Prasoon:与结构填充无关:&amp;s1.bint*,结构中的填充对指针运算如何与int* 一起使用没有影响。跨度>
  • @Steve Jessop:没错。加一个你的评论。
  • @Steve:是的,你是对的。可能我在想别的东西。
  • 我在 ubuntu 中使用 gcc

标签: c struct


【解决方案1】:

您的打印代码可能有问题。

#include <stdio.h>

struct st
{
 char a;
 short c;
 int b;
};

struct st s1;

int main() {
    printf("%p\n", (void*)(&s1.b));
    printf("%p\n", (void*)(&s1.b - 1));
    printf("%p\n", (void*)(&s1.b - 2));
}

输出:

0x403024
0x403020
0x40301c

【讨论】:

  • 将结构 s1 声明为全局
  • @C 学习者:将s1 声明为全局不会改变行为(指针算术定义非常明确,并且规范中没有任何部分允许在此处干预特定于实现的细节)。
  • @C 学习者:这有什么关系?
  • 如果我将其更改为本地,它的行为会有所不同。我正在使用 gcc
  • 你是什么意思它的行为不同?它会打印不同的地址(这很好),或者它表现出您在 OP 中描述的神秘行为?
【解决方案2】:

很可能你打印错了:

#include <stdio.h>

struct st
{
   char a;
   short c;
   int b;
};
struct st s;

int main(void)
{
    printf("s: %p\n", (void *)&s);
    printf("s.a: %p\n", (void *)&s.a);
    printf("s.b: %p\n", (void *)&s.b);
    printf("s.b-1: %p\n", (void *)(&s.b-1));
    printf("s.b-2: %p\n", (void *)(&s.b-2));
    return 0;
}

为我打印:

s: 0x100001068
s.a: 0x100001068
s.b: 0x10000106c
s.b-1: 0x100001068
s.b-2: 0x100001064

注意事项:

  • 指向结构的指针 == 指向结构的第一个元素的指针(由 C 标准保证),
  • 我正在打印带有"%p" 格式字符串的指针。 "%p" 需要void *,并且由于printf 是一个可变参数函数,在这种情况下我需要将printf 的参数转换为void *

上面的程序为你打印了什么?

编辑:根据您稍后发布的实际打印代码:&amp;s1.b&amp;s1.b-1 的值不同。 &amp;s1.b-1&amp;s1 的值相同。答案是:这是偶然发生的。在您的情况下,有结构填充,sizeof(short)+sizeof(char) 恰好≤sizeof(int)。如果您在一台任何这些假设都无效的机器上,您将不会看到这种行为。我敢肯定,如果您在代码中将 charshort 更改为 int&amp;s1.b-1 在打印时将等于 &amp;s1

最后,您应该在打印之前将指针转换为void *

printf("%p %p \n",(void *)((&s1.b)-1), (void *)&s1);

【讨论】:

    【解决方案3】:

    如果s1.b的地址是0x804a01c,那么&s1.b-2应该是0x804a014(假设int是4字节),而不是0x804a018。可能是你报地址的时候弄错了?

    【讨论】:

    • 您的意思是 4 个字节,而不是 32 位 :-)。 4 字节 == 32 位 iff CHAR_BIT == 8.
    【解决方案4】:

    感谢您发布代码。现在我看到了这个问题。这是因为填充。也就是说:

    printf("sizeof(char): %d\n", sizeof(char));
    printf("sizeof(short): %d\n", sizeof(short));
    printf("sizeof(int): %d\n", sizeof(int));
    printf("sizeof(struct st): %d\n", sizeof(struct st));
    

    在我的机器上打印

    1
    2
    4
    8
    

    你可能会想,sizeof(struct st) 不应该是1 + 2 + 4 = 7 吗?这当然是一个合理的想法,但由于alignment issuesac 之间存在填充。因此,在内存中,结构体如下所示(相对于结构体的第一个字节):

    0x00000000: char                 a
    0x00000001: padding
    0x00000002: first byte of short  c
    0x00000003: second byte of short c
    0x00000004: first byte of int    b
    0x00000005: second byte of int   b
    0x00000006: third byte of int    b
    0x00000007: fourth byte of int   b
    

    因此(相对于&amp;s1):

    &s1.b - 1 is ((long)&s1.b) - sizeof(int) = 4 - 4 = 0 = &s1
    

    这就是&amp;s1&amp;s1.b - 1 将打印相同地址的原因。特别是如果

    &s1 = 0x804a01c
    

    然后

    &s1.b = 0x804a01c + 0x00000004 = 0x804a020
    

    &s1.b - 1 = 0x804a020 - 0x00000004 = 0x804a01c
    

    &s1.b - 2 = 0x804a020 - 0x00000008 = 0x804a018
    

    最后请注意,这是特定于实现的行为。这不是便携式的!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-05
      • 1970-01-01
      • 2017-09-27
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多