【问题标题】:evaluation of operand in sizeof operator在 sizeof 运算符中计算操作数
【发布时间】:2010-08-24 06:29:32
【问题描述】:

由于 sizeof 运算符评估操作数是否是 VLA,所以我尝试将其测试为:

#include<stdio.h>
int main(void)
{
  int sz=20,i=0,j=0;
  int arr[sz];
  printf("%d\n",sizeof((++i,sz)));
  printf("%d\n",sizeof((++j,arr)));
  printf("%d\n%d\n",i,j); 
}  

我认为我不会增加,因为 sz 不是 VLA,但 j 会增加,因为 arr 是 VLA。
但是在输出中,i 和 j 都没有增加。

【问题讨论】:

  • 这是一个关于 C 而不是 C++ 的问题。 C++ 中不存在 VLA。
  • 哦,其他人将其标记为 C++。坏别人。

标签: c sizeof


【解决方案1】:

引用my answer to another question:

“转换”是由于减法运算符。您可以使用逗号运算符看到类似的,也许更令人惊讶的结果:

printf("%zu\n", sizeof(1, a));

还将打印sizeof(int *),因为逗号运算符会导致在值上下文中使用。

基本上,由于逗号运算符,the type of arr 是一个指针,VLA 的大小没有出现。有关详细信息,请参阅我的链接答案。

【讨论】:

  • 好吧..我明白..那么有没有一种方法可以利用“sizeof 评估操作数,如果它是 vLA”这一事实来增加或修改其他一些操作数,就像我在这里尝试做的那样?
  • @Happy:我不会称之为“利用”,它更像是“滥用sizeof 运算符”。你到底想做什么?
【解决方案2】:

解释不多,但我怀疑这是对逗号运算符的一些编译器优化。逗号操作的值是最后一个表达式的值。由于编译器知道 sizeof 是一元运算符并显示为逗号操作,它不会费心计算除最后一个表达式之外的任何表达式(不管最后一个是否是对 VLA 的引用)。

我写了一些测试程序(Ubuntu 9.04 上的 gcc 4.3.3):

$ cat test.c # with sizeof

#include <stdio.h>
int main(void)
{
    int x = 0;
    printf("%d\n",
            sizeof( printf("%s%d\n", "comma!", ++x), x));
}

$ gcc -S test.c

$ cat test.s

        .file   "test.c"
        .section    .rodata
.LC0:
        .string "%d\n"
        .text
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
        subl    $36, %esp
        movl    $0, -8(%ebp)
        movl    $4, 4(%esp)
        movl    $.LC0, (%esp)
        call    printf
        addl    $36, %esp
        popl    %ecx
        popl    %ebp
        leal    -4(%ecx), %esp
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
        .section    .note.GNU-stack,"",@progbits

请注意缺少字符串文字和第二个 printf() 调用。

$ cat test-alt.c # 没有 sizeof

#include <stdio.h>
int main(void)
{
    int x = 0;
    printf("%d\n",
                  ( printf("%s%d\n", "comma!", ++x), x));
}

$ gcc -S test-alt.c

$ cat test-alt.s

        .file   "test-alt.c"
        .section    .rodata
.LC0:
        .string "comma!"
.LC1:
        .string "%s%d\n"
.LC2:
        .string "%d\n"
        .text
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
        subl    $36, %esp
        movl    $0, -8(%ebp)
        addl    $1, -8(%ebp)
        movl    -8(%ebp), %eax
        movl    %eax, 8(%esp)
        movl    $.LC0, 4(%esp)
        movl    $.LC1, (%esp)
        call    printf
        movl    -8(%ebp), %eax
        movl    %eax, 4(%esp)
        movl    $.LC2, (%esp)
        call    printf
        addl    $36, %esp
        popl    %ecx
        popl    %ebp
        leal    -4(%ecx), %esp
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
        .section    .note.GNU-stack,"",@progbits

它可能记录在某处,但我不知道去哪里找。

【讨论】:

    【解决方案3】:

    sizeof 在编译时计算。在 C99 中,对于可变长度数组,它将等到运行时。检查this answer 来回答类似的问题。

    【讨论】:

      【解决方案4】:

      编译器知道数组大小:显然是 20。我不认为 sz 是 VLA。尝试使用数组大小​​作为函数参数,例如:

      无效函数(整数大小) { int arr[大小]; ... }

      顺便说一句,要了解会发生什么,建议阅读编译器生成的汇编代码。检查 sizeof 是否在编译时已被常量替换。

      【讨论】:

      • 编译器在这种情况下确实知道数组大小,但它在技术上是一个 VLA,因为 sz 是一个变量,而不是一个常量。即使它是一个常量(const int sz=20;),这也不会使数组成为 VLA(尽管它总是具有相同的大小)。
      猜你喜欢
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 2018-12-30
      • 1970-01-01
      • 2021-04-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多