C - 是不确定的不确定值吗?

dte*_*ech 12 c undefined undefined-behavior language-lawyer

根据这篇文章,不确定的价值是:

3.17.2
1 indeterminate value
either an unspecified value or a trap representation
Run Code Online (Sandbox Code Playgroud)

根据谷歌的说法,不确定性的定义是:

  • 不确定,已知或已建立
  • 可疑; 模糊.

根据thefreedictionary,可确定的是:

  • 能够被确定

根据merriam-webster,确定(在特定的上下文中)是:

  • 通过调查,推理或计算找出或做出决定

因此,常识规定尽管在编译期间不确定值是未知的,但它在运行时是完全可确定的,例如,您总是可以读取占用该内存位置的任何事件.

还是我错了?如果是这样,为什么?

编辑:为了澄清,我发布了与用户试图说服不确定值不确定的用户之间的争论,我非常怀疑.

编辑2:澄清,通过"可确定的"我并不意味着稳定或可用的值,即使它是未初始化的内存的垃圾值,仍然可以确定该垃圾的价值.我的意思是,试图确定这个价值仍会产生一些价值,而不是......没有行动.所以这个值必须来自一些内存,分配为仍然不确定的值的存储,我高度怀疑编译器实际上会使用一个随机数生成器只是为了提出一些任意值.

AnT*_*AnT 17

它不确定的事实不仅意味着它在第一次读取时是不可预测的,它还意味着它不能保证稳定.这意味着两次读取相同的未初始化变量不能保证产生相同的值.因此,您无法通过阅读来"确定"该值.(参见DR#260,从2004年开始对该主题进行初步讨论,DR#451在2014年重申该位置.)

例如,a可以指定变量来占用R1具有特定时间帧(而不是存储器位置)的CPU寄存器.为了建立最佳的可变寄存器分配调度,"对象寿命"的语言级概念不够精确.CPU寄存器由优化编译器管理,基于更精确的"值寿命"概念.当变量被赋值为确定值时,值生存期开始.当最后一次读取先前分配的确定值时,值寿命结束.值生存期确定变量与特定CPU寄存器关联的时间范围.R1b.尝试a在其值生命周期之外读取未初始化的变量实际上可能会导致读取变量b,这可能是主动更改.

在此代码示例中

{
  int i, j;

  for (i = 0; i < 10; ++i)
    printf("%d\n", j);

  for (j = 0; j < 10; ++j)
    printf("%d\n", 42);
}
Run Code Online (Sandbox Code Playgroud)

编译器可以很容易地确定,即使对象寿命ij重叠,值寿命完全不重叠,这意味着两者ij能得到分配到同一个CPU寄存器.如果发生类似的事情,您可能很容易发现第一个循环打印i每次迭代的不断变化的值.这与j不确定的价值观完全一致.

请注意,此优化不一定需要CPU寄存器.另一个例子,一个关注保留有价值的堆栈空间的智能优化编译器可能会分析上面代码示例中的值生存期并将其转换为

{
  int i;

  for (i = 0; i < 10; ++i)
    printf("%d\n", <future location of j>);
}

{
  int j;

  for (j = 0; j < 10; ++j)
    printf("%d\n", 42);
}
Run Code Online (Sandbox Code Playgroud)

使用变量ij在不同时间占用内存中的相同位置.在这种情况下,第一个循环可能会再次打印i每次迭代的值.

  • @ddriver:是的,但那不是重点.关键是变量和寄存器之间的紧密关系不会开始,直到*确定*值被*写入变量.*读*变量不会开始这种关系.因此,在那个时刻之前,由于任何外部原因,寄存器可以根据需要自由更改,这意味着每次读取可能很容易产生不同的值. (3认同)
  • @ddriver:我不确定你的"寄存器变量"是什么意思.任何变量都可以在您不知情的情况下存储在寄存器中,这意味着您可以从任何变量中观察相同的行为.此外,理论上可以应用相同的技术来节省堆栈存储器,因此即使没有任何与寄存器相关的优化也可以观察到效果. (2认同)
  • 出于好奇,我测试了你的示例代码:用`gcc`打印所有`j`等于'0`,但`clang`打印出2或3个不同的值,即使在`-O0`版本中也是如此. (2认同)

oua*_*uah 11

连续两次读取不确定值可以给出两个不同的值.此外,读取不确定的值会在陷阱表示的情况下调用未定义的行为.

DR#260中,C委员会写道:

不确定的值可以由任何位模式表示.C标准规定不要求对代表给定值的位的两次检查将观察到相同的位模式,只是每次的观察模式将是该值的有效表示.

[...]在达到我们的响应时,我们注意到要求不确定值的不可变位模式会减少优化机会.例如,如果包含它们的内存被分页,则需要跟踪不确定值的实际位模式.这对优化程序来说似乎是一种不必要的限制,对程序员没有任何补偿性好处.

  • @ddriver通常事情是未定义的,以便为编译器提供一些空间来执行性能和内存优化.(也许我现在还无法想到其他好处.)至于为什么,除了C语言的设计者非常重视这些好处以允许这种权衡之外,没有任何明确的答案.其他语言的UD较少,因为他们的设计师更重视可预测性.这不是C的设计者的错误(也不是疏忽或松散的结束),它只是一种语言设计决策. (4认同)
  • @ddriver我明白你在说什么,我认为前3位的回答者也理解它.但问题是,如果你读取一个未初始化的变量,编译器甚至可能不会为你带来(垃圾)二进制表示.请参阅Pascal的链接,它解决并准确解释了您的要求. (3认同)
  • @ddriver C11表示读取未初始化的自动对象会调用未定义的行为*6.3.2.1p2)"如果左值指定了一个可以使用寄存器存储类声明的自动存储持续时间的对象(从未使用过其地址),那么对象未初始化(未使用初始化程序声明,并且在使用之前未对其进行任何分配),行为未定义."*有关更多信息,请参阅DR#338 http://www.open-std.org/jtc1/ SC22/WG14/WWW /文档/ dr_338.htm (2认同)

Pas*_*uoq 5

C90标准清楚地表明,从不确定的位置读取是不确定的行为.更新的标准不再那么清楚(不确定的内存是"未指定的值或陷阱表示"),但编译器仍然以一种只有在读取不确定的位置是未定义的行为时才可行的方式进行优化,例如,乘以未初始化变量中的整数乘以2会产生奇数结果.

所以,简而言之,不,你无法阅读任何占据不确定记忆的事情.