【问题标题】:Using uninitialized variable without invoking undefined behavior使用未初始化的变量而不调用未定义的行为
【发布时间】:2020-02-12 08:20:31
【问题描述】:

来自 6.3.2.1(强调我的)

如果左值指定了一个自动存储持续时间的对象 可以用寄存器存储类声明(从来没有 它的地址被占用),并且该对象未初始化(未声明 使用初始化程序并且之前没有对其进行分配 使用),行为未定义。

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

int x; 

printf("just a dummy pointer print %p", &x);  //taking the address to break 6.3.2.1 UB condition

if (x == 2)
{
    print("x uninitialized value: %d", x);
} 

根据 6.3.2.1,if (x == 2) 中没有未定义的行为,我使用未初始化对象的值。 如果这是真的,并且这里没有 UB,那么定义的行为是什么?根据标准,x 我应该期待什么?

【问题讨论】:

  • 如果您将引用的部分放在上下文中,也许我们可以给出客观的答案?例如,“行为”指的是什么?
  • @Adrian 这是 C 标准,而不是一些异国情调的书。
  • 比 6.3.2.1 不相关 所以?这并不排除出于其他原因的未定义行为。这就像告诉那个闯红灯把你拦下的警察,“但我没有超速!”。
  • 请注意,您不需要打印指针。像&x; 这样的无所事事声明就足以满足它不是 UB 的条件。
  • 您和许多其他绝对专业人士可能通常会知道您对“6.3.2.1(强调我的)”的含义,但您能否对您所指的内容给出绝对参考?是 ANSI-C 实现吗?

标签: c language-lawyer addressof lvalue-to-rvalue register-keyword


【解决方案1】:

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

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

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

相关段落来自C standard

第 3.19 节:

3.19.2

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

3.19.3

1 unspecified value 本国际标准不要求的相关类型的有效值 在任何情况下都选择了哪个值

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

3.19.4

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

第 6.7.9p10 节:

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

【讨论】:

  • 请注意,在典型的实际实现中,没有填充位,整数类型具有全范围的二进制补码表示,这意味着不存在陷阱表示。这些属性可通过limits.h 宏和其他方式测量/观察。
  • 带回奇偶校验位!
【解决方案2】:

该标准使用“未定义行为”一词来描述一般情况,其中绝大多数实现将以相同的可预测的一般方式表现,但某些特定实现可能会通过表现不同来更好地为其客户服务。

考虑以下函数:

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],同时让这些结构的其他元素保留它们之前保留的任何内容。他们没有试图准确描述应该允许什么样的优化,而是简单地假设实施将寻求最好地满足客户的需求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-28
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-07
    相关资源
    最近更新 更多