尝试在没有点运算符的情况下打印结构变量

Trying to print structure variable without dot operator

我正在尝试不使用任何点或箭头运算符来简单地打印结构变量。

#include<stdio.h>
int main()
{
    struct test{
        char A[10];
        float b;
    }obj = {"Testing",3.14};

    printf("%u\n",&obj);
    printf("%u\n",&obj.A);
    printf("%u\n",obj);
}

输出

6422288
6422288
1953719636

见第三条printf语句。我只是想打印 obj 的值。现在我知道这是我不应该做的事情,但我只是好奇。上面两个语句只是简单地打印结构变量的起始地址(假设这里不涉及预结构填充)但我无法理解情况 3 中发生的情况。如果它是一个结构数组而不是简单地写 obj 将提供该数组的基地址,但这里的逻辑是什么?

  • printf("%u\n",&obj); 打印结构开始的地址,解释为无符号整数。
  • printf("%u\n",&obj.A); 打印 obj.A 的地址,解释为无符号整数
  • printf("%u\n",obj); 打印结构的值,解释为无符号整数。

无论如何,按照this question的建议,打印指针值最好使用%p

这都是未定义的行为 (UB)

printf("%u\n",&obj); 是 UB,因为指针未指定匹配 "%u"。其他 2 个相同。所有 UB。

but i am unable to understand what is happening in case 3

回想一下,使用 mis-matched 打印说明符是 UB,并且可能导致 non-sense 输出,因为参数传递机制可能因类型而异。例如。 FP 值在 FP 堆栈中传递,而不是通常的结果是 %u 访问随机数据。


我建议在尝试占卜 UB 时使用匹配说明符,如 "%p" 用于地址,十六进制说明符用于数字 ("%X" "%a") 和十六进制常量 (0x123, 1.23p45) .

#include<stdio.h>
int main() {
  struct test {
    char A[10];
    float b;
  } obj = { "Testing", 3.14p0 };

  printf("%p\n", (void *) &obj);
  printf("%p\n", (void *) &obj.A);

  // Still UB, but if you get some output, possible easier to correlate to what is happening on your machine.
  printf("%llX\n", obj);
}

根据输出,我知道你的机器是小端字节序的,有 4 个字节 ints。

在 ASCII 中,“测试”是 { 0x54, 0x65, 0x73, 0x74 ... }。当您告诉 printfunsigned int 使用 %u 格式说明符时,它会查看 obj“值”的前 4 个字节。解释为小端,这是 0x74736554,以 10 为基数是 1953719636,您看到输出的值。

struct的第一个元素的地址与struct对象本身的地址相同1,所以如果你解释obj 的地址作为 char *,那么你可以像这样打印存储在第一个成员中的字符串:

printf( "%s\n", (char *) &obj ); 

然而...

虽然像这样的技巧可能会让您深入了解事物的幕后工作原理,但在“真实”代码中应该避免使用它们。如果您按预期使用成员访问运算符,每个人的生活都会更轻松:

printf( "%s\n", obj.A );

  1. 根据 C 2011 Online Draft,6.2.7.1/15:“在结构对象中,non-bit-field 成员和 bit-fields 所在的单元 reside 的地址按照声明的顺序递增。一个指针 适当转换的结构对象指向其初始成员(或者如果该成员是 bit-field,然后到它所在的单元),反之亦然。 可能有未命名的 在结构对象内填充,但不在其开头。"