C 使用未初始化的变量而不调用未定义的行为

C 使用未初始化的变量而不调用未定义的行为,c,language-lawyer,addressof,lvalue-to-rvalue,register-keyword,C,Language Lawyer,Addressof,Lvalue To Rvalue,Register Keyword,从6.3.2.1(重点矿山) 如果左值指定了自动存储持续时间的对象 可以用寄存器存储类声明(从未声明过 该对象未初始化(未声明) 使用初始值设定项,且之前未对其进行赋值 要使用),该行为未定义 这意味着,如果无法使用寄存器存储类声明自动对象(获取其地址): 根据6.3.2.1,如果(x==2)使用未初始化对象的值,则中没有未定义的行为。 如果这是真的,并且这里没有UB,那么定义的行为是什么?根据标准,在x中我应该期望什么呢?在这种情况下,因为x已经获取了它的地址,所以行为不是严格未定义的。此时x

从6.3.2.1(重点矿山)

如果左值指定了自动存储持续时间的对象 可以用寄存器存储类声明(从未声明过 该对象未初始化(未声明) 使用初始值设定项,且之前未对其进行赋值 要使用),该行为未定义

这意味着,如果无法使用寄存器存储类声明自动对象(获取其地址):

根据6.3.2.1,如果(x==2)使用未初始化对象的值,则
中没有未定义的行为。

如果这是真的,并且这里没有UB,那么定义的行为是什么?根据标准,在
x
中我应该期望什么呢?

在这种情况下,因为
x
已经获取了它的地址,所以行为不是严格未定义的。此时
x
的值是不确定的。这意味着该值是陷阱表示法未指定

如果
x
碰巧包含陷阱表示,则行为未定义,否则该值未指定,这意味着可以打印任何有效值

此外,您可能遇到的大多数系统在整数类型中没有任何填充位,这意味着在该实现中没有陷阱表示,并且该值将始终未指定

本节的相关段落:

第3.19节:

3.19.2

1不确定值未指定值或陷阱表示

3.19.3

1未指定值本国际标准未要求的相关类型的有效值 在任何情况下选择哪个值

2注:未指定的值不能是陷阱表示

3.19.4

1陷阱表示法不需要表示对象类型值的对象表示法

第6.7.9p10节:

如果没有指定具有自动存储持续时间的对象 显式初始化,其值不确定


该标准使用术语“未定义的行为”,除其他外,用于描述绝大多数实现将以相同的可预测的一般方式运行,但某些特定实现可能通过不同的行为更好地服务于其客户的一般情况

考虑以下功能:

struct foo { unsigned char dat[256]; };

struct foo x,y;

void test(int a, int b)
{
  struct foo temp;
  temp.dat[a] = 1;
  temp.dat[b] = 2;
  x=temp;
  y=temp;
}

我认为标准的作者不想要求程序员在存储之前完全初始化
temp
,但我也不认为他们想禁止实现简单地写入
x.dat[a]
y.dat[a]
x.dat[b]
,和
y.dat[b]
,而让那些结构的其他元素保留他们之前持有的东西。他们没有试图准确描述应该允许哪些类型的优化,而是简单地假设实现将寻求最好地满足客户的需求。

如果您将引用的部分放在上下文中,也许我们可以给出客观的答案?例如,“行为”指的是什么?@Adrian这是C标准,不是什么异国情调的书。6.3.2.1与此无关?这并不排除其他原因导致的未定义行为。这就像告诉警察你闯红灯停车,“但我没有超过限速!”注意,你不需要打印指针。只是一个像
&x;这样的“不做任何事”语句足以满足不属于UB的条件。通常情况下,您和许多其他绝对专业人士可能会知道“6.3.2.1(强调我的)”的含义,但您能否给出您所指内容的绝对参考?是ANSI-C实现吗?请注意,在典型的实际实现中,没有填充位,整数类型具有全范围的两个补码表示,这意味着陷阱表示不存在。这些属性可以通过
limits.h
宏和其他方式进行测量/观察。返回奇偶校验位!
struct foo { unsigned char dat[256]; };

struct foo x,y;

void test(int a, int b)
{
  struct foo temp;
  temp.dat[a] = 1;
  temp.dat[b] = 2;
  x=temp;
  y=temp;
}