尝试在没有点运算符的情况下打印结构变量
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 个字节 int
s。
在 ASCII 中,“测试”是 { 0x54, 0x65, 0x73, 0x74 ... }
。当您告诉 printf
对 unsigned int
使用 %u
格式说明符时,它会查看 obj
“值”的前 4 个字节。解释为小端,这是 0x74736554,以 10 为基数是 1953719636,您看到输出的值。
struct
的第一个元素的地址与struct
对象本身的地址相同1,所以如果你解释obj
的地址作为 char *
,那么你可以像这样打印存储在第一个成员中的字符串:
printf( "%s\n", (char *) &obj );
然而...
虽然像这样的技巧可能会让您深入了解事物的幕后工作原理,但在“真实”代码中应该避免使用它们。如果您按预期使用成员访问运算符,每个人的生活都会更轻松:
printf( "%s\n", obj.A );
- 根据 C 2011 Online Draft,6.2.7.1/15:“在结构对象中,non-bit-field 成员和 bit-fields 所在的单元
reside 的地址按照声明的顺序递增。一个指针
适当转换的结构对象指向其初始成员(或者如果该成员是
bit-field,然后到它所在的单元),反之亦然。 可能有未命名的
在结构对象内填充,但不在其开头。"
我正在尝试不使用任何点或箭头运算符来简单地打印结构变量。
#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 个字节 int
s。
在 ASCII 中,“测试”是 { 0x54, 0x65, 0x73, 0x74 ... }
。当您告诉 printf
对 unsigned int
使用 %u
格式说明符时,它会查看 obj
“值”的前 4 个字节。解释为小端,这是 0x74736554,以 10 为基数是 1953719636,您看到输出的值。
struct
的第一个元素的地址与struct
对象本身的地址相同1,所以如果你解释obj
的地址作为 char *
,那么你可以像这样打印存储在第一个成员中的字符串:
printf( "%s\n", (char *) &obj );
然而...
虽然像这样的技巧可能会让您深入了解事物的幕后工作原理,但在“真实”代码中应该避免使用它们。如果您按预期使用成员访问运算符,每个人的生活都会更轻松:
printf( "%s\n", obj.A );
- 根据 C 2011 Online Draft,6.2.7.1/15:“在结构对象中,non-bit-field 成员和 bit-fields 所在的单元 reside 的地址按照声明的顺序递增。一个指针 适当转换的结构对象指向其初始成员(或者如果该成员是 bit-field,然后到它所在的单元),反之亦然。 可能有未命名的 在结构对象内填充,但不在其开头。"