c/c++语言开发共享为什么零长度VLA UB?

2011年标准明确规定……

6.7.6.2数组声明符

这是设计的,但以下代码似乎是合理的。

 size_t vla(const size_t x) { size_t a[x]; size_t y = 0; for (size_t i = 0; i < x; i++) a[x] = i; for (size_t i = 0; i < x; i++) y += a[i % 2]; return y; } 

Clang似乎为它生成合理的x64程序集(没有优化)。 显然索引零长度VLA没有意义,但访问超出边界会调用未定义的行为。

为什么零长度数组未定义?

     int i = 0; int a[i], b[i]; 

    a == b ? 它不应该 – 它们是不同的对象 – 但避免它是有问题的。 如果你无条件地在ab之间留下间隙,你就会在i > 0情况下浪费空间。 如果你检查i == 0并且只留下间隙,那么你就是在i > 0情况下浪费时间。

    多维数组会变得更糟:

     int i = 0; int a[2][i]; 

    你可以在两个变量之间填充,但你可以在哪里填充? 如果不打破sizeof (int[2][i]) == 2 * i * sizeof (int)的不变量,就无法做到这一点。 如果你没有填充,那么a[0]a[1]具有相同的地址,并且你打破了一个不同的重要不变量。

    这是一个不值得定义的头痛。

    虽然我们可以看到gcc支持零长度数组扩展 ,但显然它们很有用。 从标准的角度来看,它似乎会产生一些问题,因为现在每个对象都应该有一个唯一的地址。 我们可以从C99和C11标准草案6.5.9中看到这一点。平等运营商说:

    两个指针比较相等,当且仅当两个都是空指针时,两者都是指向同一对象的指针(包括指向对象的指针和在其开头的子对象)或函数,两者都是指向同一数组的最后一个元素之后的指针object,或者一个是指向一个数组对象末尾的指针,另一个是指向另一个数组对象的开头的指针,该数组对象恰好跟随地址空间中的第一个数组对象.94)

    因此,这需要一些特殊的shell,并且可以使用替代方法提供大多数有用性,例如flexibile数组。

    它也可能需要在其他地方进行更改,因为MM在6.3.2.1 Lvalues,数组和函数指示符中指出数组指针衰减:

    […]具有类型”数组类型”的表达式将转换为类型为”指向类型’的指针的表达式,指向数组对象的初始元素,而不是左值[… ]

    这似乎需要几个非平凡的变化才能获得最小的额外收益。

    看C标准:

    C11- 6.7.6.2数组声明符(p1):

    […]如果表达式是常量表达式, 则其值大于零 。 […]

    (P5):

    如果size是一个不是整数常量表达式的表达式:如果它出现在函数原型范围的声明中,则将其视为*被替换为* ; 否则, 每次评估它时其值大于零 。 […]

    4.符合性:

    如果违反了约束或运行时约束之外出现的“应该”或“不应该”的要求,则行为是不确定的 。 未定义的行为在本国际标准中以“未定义的行为”或省略任何明确的行为定义的方式另有说明。 这三者之间的重点没有区别; 他们都描述了“未定义的行为”

    因此,声明零大小的数组会导致程序的未定义行为。

      以上就是c/c++开发分享为什么零长度VLA UB?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/546017.html

      (0)
      上一篇 2021年1月10日
      下一篇 2021年1月10日

      精彩推荐