不同 C 标准中的结构体值

pep*_*pep -1 c struct

在不同的 C 标准中应该打印什么 C 代码?

struct X { int a; char b[4]; };

struct X x, y; struct X *px;

printf("%x %x\n", x, &x);   // what mean x in this context?  suppose we get 0x12b45 and 0x34235
printf("%d\n", x == 0x12b45 ? 1 : 0)
px = &x;
x = *px;
printf("%x %x\n", x, *px);
x = y
printf("%x %x\n", x, y);
Run Code Online (Sandbox Code Playgroud)

换句话说,结构体的价值是什么?或者更好地说,结构解析为什么值?使用数组进行类比,数组名称解析为第一个数组项的值,什么值解析为结构名称?

int a[3];

printf("%x %x\n", a, a[0]);  // prints the same value twice

struct s { int a; } b;

printf("%x\n", b);  // what value is printed?
Run Code Online (Sandbox Code Playgroud)

@David Grayson 要求提供一个最小的可重复示例,在这里:

#include <stdio.h>
#include <stdlib.h>

struct X { int a;  char b[4]; };

struct X x, y; struct X *px;

void main(int argc, char *argv[]) {
    printf("%x %x\n", x, &x);   // what mean x in this context?  
    printf("%p %p\n", x, &x);  
    px = &x;
    x = *px;
    printf("%x %x\n", x, *px);
    x = y;
    printf("%x %x\n", x, y);
    
    int a[3];

    printf("%x %x\n", a, &a[0]);  // prints the same value twice

    struct s { int a; } b;

    printf("%x %x\n", b, b.a);  // what value is printed?
}
Run Code Online (Sandbox Code Playgroud)

?我删除了带有/运算符的行:,因为它在编译时不会出现有关尝试使用结构进行操作的错误。

使用TCC编译该代码的结果是这样的:

struct X { int a; char b[4]; };

struct X x, y; struct X *px;

printf("%x %x\n", x, &x);   // what mean x in this context?  suppose we get 0x12b45 and 0x34235
printf("%d\n", x == 0x12b45 ? 1 : 0)
px = &x;
x = *px;
printf("%x %x\n", x, *px);
x = y
printf("%x %x\n", x, y);
Run Code Online (Sandbox Code Playgroud)

我对结果的理解是这样的,当然打印指针或十六进制数字提供相同的值,只是格式不同,所以我将忽略指针输出。

  • 第一个打印显示一个数字,它是变量(结构体X)0的地址,“奇怪”的是第一个,我认为是结构体X的成员的值,初始化为0,因为x是一个全局变量。x0

  • 第二个 print 打印相同的值,0因为它是相同的x变量,通过它自己的 id 和指向该x变量的指针进行访问。

  • 即使在打印两个不同的 struct X 变量时,第三个 print 也会打印相同的值,x并且y,因为我之前已将变量y(一个 struct X)分配给变量x,所以它们都是相同的变量,并且它被初始化为0,因为是全局的,但问题是,当将一个结构分配给另一个结构时,它是复制所有字节还是简单地分配指针?

  • 第四次打印涉及以通常的行为打印数组

  • 第五个打印很有趣,因为它打印整个结构体和第一个(也是唯一的)成员,并且打印相同的值 6。为什么是 6?我的猜测是,这次结构变量 b 是一个局部变量,因此没有初始化,所以我们得到了垃圾。这里的要点是使用结构变量似乎与使用第一个成员相同,类似于数组,但我不知道这是否是标准行为或者它取决于编译器或 C 标准。

所以我的猜测是使用结构变量作为符号解析为与结构的第一个成员相同的值,这与数组的工作方式类似。我认为这与 @Eric Postpischil 所说的一致。

Eri*_*hil 6

C 标准没有正式定义结构体的值,尽管结构体必须具有值,因为标准指定的某些行为需要它,例如将一个结构体对象的值分配给另一个结构体对象。结构类型是成员的序列,因此结构的值在概念上是其成员值的元组。

\n

以下参考C 2018标准。我预计该标准的其他版本不会有重大变化。

\n
\n

printf("%x %x\\n" , x, &x); // what mean x in this context? suppose we get 0x12b45 and 0x34235

\n
\n

此代码的行为不是由 C 标准定义的,因为%x指定为采用unsigned int参数 (7.21.6.1 8),并且 \xe2\x80\x9c\xe2\x80\xa6 如果任何参数不是对应的正确类型转换规范,行为未定义\xe2\x80\x9d (7.21.6.1 9)。

\n
\n

printf("%d\\n" , x == 0x12b45 ? 1 : 0)

\n
\n

==编译此代码必须产生一条诊断消息,因为它违反了6.5.9 2 中的约束:

\n
\n

应满足下列条件之一:

\n

\xe2\x80\x94 两个操作数都是算术类型;

\n

\xe2\x80\x94 两个操作数都是指向兼容类型的限定或非限定版本的指针;

\n

\xe2\x80\x94 一个操作数是指向对象类型的指针,另一个是指向对象类型的限定或非限定版本的指针void指针 或者

\n

\xe2\x80\x94 一个操作数是指针,另一个是空指针常量。

\n
\n

如果编译器确实接受该表达式,则该行为不是由 C 标准定义的。

\n
\n

px = &x;
x = *px;

\n
\n

设置px为指向后x,这仅设置x为它自己的值。

\n
\n

printf("%x %x\\n" , x, *px);

\n
\n

如上所述,该代码的行为不是由 C 标准定义的。

\n
\n

x=y

\n
\n

这设置x为具有值y(在一定程度上它有一个;讨论未初始化的对象超出了这个答案的范围)。执行后, 的每个成员x将立即具有 的相应成员的值yx和中的任何填充字节y可能不同,因为填充字节的内容x可能不同,因为根据 6.2.6.1 6 未指定

\n
\n

printf("%x %x\\n" , x, y);

\n
\n

如上所述,该代码的行为不是由 C 标准定义的。

\n