【问题标题】:VLAs and side-effect in sizeof's operandsizeof 操作数中的 VLA 和副作用
【发布时间】:2023-04-09 13:00:01
【问题描述】:

我知道sizeof 从不评估其操作数,除非在所述操作数是 VLA 的特定情况下。或者,我以为我知道。

void g(int n) {
    printf("g(%d)\n", n);
}

int main(void) {
    int i = 12;

    char arr[i]; // VLA

    (void)sizeof *(g(1), &arr); // Prints "g(1)"
    (void)sizeof (g(2), arr);   // Prints nothing

    return 0;
}

发生了什么事?

以防万一,这是在 Coliru 上使用 GCC 5.1 编译的。

【问题讨论】:

    标签: c sizeof side-effects variable-length-array


    【解决方案1】:

    看来我应该在发帖前三思而后行,因为它在我发帖后立即让我印象深刻。

    我对 sizeof 如何与 VLA 交互的理解实际上是正确的,正如以下引用所证实的(感谢 @this !):

    6.5.3.4 sizeof 和 _Alignof 运算符
    如果操作数的类型是变长数组类型,则计算操作数;否则,不计算操作数,结果为整数常量

    这不是导致这种(对我而言)令人惊讶的行为的原因。

    (void)sizeof (g(2), arr);
    

    在(g(2), arr) 子表达式中,逗号运算符触发arr 的数组到指针衰减。因此,sizeof 的操作数不再是 VLA,而是一个普通的 char*,它回退到不评估其操作数。

    Apparently 这种行为在 C++ 中已被更改,其中逗号运算符不再衰减数组。

    【讨论】:

    • 您可能想在某处添加: 6.5.3.4 sizeof 和 _Alignof 运算符 如果操作数的类型是可变长度数组类型,则计算操作数;否则,操作数不会被计算并且结果是一个整数常量。所以狂热的读者会感到困惑。
    • 也许我错过了什么,但是; sizeof() 是编译时运算符,而不是运行时函数。所以 (void)sizeof() 是无意义的,因为 sizeof() 返回一个 size_t(实际上是一个 long int)值,而不是指针,并且 sizeof() 只需要一个参数。
    • @user3629249 sizeof 是一个严格的编译时运算符,不会评估其操作数,except 当其操作数是 VLA 时,它会评估它,在运行。 (void) 演员表与指针无关:它明确丢弃刚刚计算的值 sizeof。它实际上并不影响程序的行为,但比仅仅计算一个表达式,然后掉在地板上(GCC 会产生一个警告)更好的风格。 [续]
    • @user3629249 最后,不要让语法欺骗你:sizeof 是一个运算符,而不是一个函数,当它的操作数是一个表达式时它不带括号(它为类型)。这里的括号优先考虑逗号运算符(它不是参数列表的逗号)。 sizeof 仍然采用单个操作数,这是括号中的结果。
    猜你喜欢
    • 2016-01-04
    • 1970-01-01
    • 1970-01-01
    • 2015-03-18
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多