【问题标题】:Can't understand why I got these results using struct offset in C不明白为什么我在 C 中使用 struct offset 得到这些结果
【发布时间】:2015-07-26 01:24:44
【问题描述】:

我在玩结构并尝试使用偏移量获取它们的值,这是我的代码

#include <stdio.h>
#include <stddef.h>

typedef struct abcd{
    int a,b;
    double c,d;
}abcd;

int main()
{
    abcd teste = {.a = 3, .b = 5, .c = 7, .d = 9};
    printf("value of a: %d  //value of b:  %d\n",*( (char*) &teste), *((char*) &teste + offsetof(abcd, b)) );
    return 0;
}

输出:value of a: 3 //value of b: 5

一切正常,但是当我将 printf 更改为

printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
//No casting to (char*) in value of a

我得到输出:value of a: 5 value of b: 1360854088

为什么会这样?

【问题讨论】:

  • 您的第二个printf 实际上是为%d 格式说明符提供完整的结构(*(&amp;teste))。这将使格式字符串中后续说明符的后续值的堆栈位置不对齐。
  • 类型转换在 C 编程中有着悠久而受人尊敬的传统,并且对于正确使用返回 void * 类型的 malloc() 之类的东西是必要的。我不确定 GRC 发生了什么。
  • @larsks 在 C 中你不应该转换 void *,尤其是 mallocvoid * 可以分配给任何非函数指针类型而无需强制转换。然而,C++ 是另一回事。
  • @GRC 在 C 中进行类型转换时,究竟违反了什么标准?
  • @GRC 讨论的不是一般的选角,而是选角void *。在 OP 的示例中,情况并非如此。

标签: c struct offset


【解决方案1】:
printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );

这会按值传递teste,这比单个 int 占用更多空间。第二个 %d 可能会从第一个 arg 的某些字节中获取输入。编译器警告清楚地表明了这一点:

$ clang-3.5 -Wall  bad-printf.c -O3 
bad-printf.c:12:48: warning: format specifies type 'int' but the argument has type 'abcd' (aka 'struct abcd') [-Wformat]
    printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
                        ~~                     ^~~~~~~~~~

$ gcc -Wall  bad-printf.c -O3 
bad-printf.c: In function ‘main’:
bad-printf.c:12:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘abcd’ [-Wformat=]
     printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
     ^

$ ./a.out 
value of a: 5  value of b: 0

$ uname -a
Linux tesla 3.19.0-22-generic #22-Ubuntu SMP Tue Jun 16 17:15:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

它还将一个单字节字符作为第三个参数(格式字符串之后的第二个参数)传递给printf。寄存器中的其他字节(或堆栈中的其他字节,如果您为过时的 32 位 x86 编译)可能是从其他东西遗留下来的。

检查汇编输出。您可能会发现来自 &amp;abcd.b 的一个字节加载,而其他字节保持不变。

你已经告诉 printf(通过使用 %d)你传递了一个完整的 int。如果您只想打印一个 8 位整数(因此它不会将填充视为数据),则需要为格式说明符添加大小前缀。

【讨论】:

    【解决方案2】:

    printf %d 但是你传递了 sturct adcd,这是一个未定义的动作,结果是未定义的,应该考虑 printf.c 实现。

    我的代码:

     typedef struct abcd{
            int a,b;
                double c,d;
    }abcd;
    
    int main()
    {
        abcd teste = {.a = 3, .b = 5, .c = 7, .d = 9}; 
        printf("value of a: %d  //value of b:  %d\n",*( (char*) &teste), *((char*) &teste + offsetof(abcd, b)) );
        printf("%d\n", offsetof(abcd, b));
        printf("value of a: %p  value of b: %p\n", ( &teste), ((char*) &teste + offsetof(abcd, b)) );
        printf("value of a: %d  value of b: %d\n", teste, *((char*) &teste));
        printf("value of a: %p  value of b: %p\n", &teste, ((char*) &teste));
        printf("value of a: %d  value of b: %d\n", teste, *((char*) &teste));
        //No casting to (char*) in value of a
        return 0;
    }
    result:
    value of a: 3  //value of b:  5
    4
    value of a: 0x7fff86f203b0  value of b: 0x7fff86f203b4
    value of a: 3  value of b: -2114388464
    value of a: 0x7fff86f203b0  value of b: 0x7fff86f203b0
    value of a: 3  value of b: -2114388464
    

    未定义的进程导致未知的结果

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多