оценка операнда в размере оператора - PullRequest
2 голосов
/ 24 августа 2010

Поскольку оператор 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 не увеличился.

Ответы [ 4 ]

4 голосов
/ 24 августа 2010

Цитируя мой ответ на другой вопрос :

«Преобразование» происходит из-за оператора вычитания. Вы можете увидеть похожий и, возможно, более удивительный результат с запятой:

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

также напечатает sizeof(int *), поскольку оператор запятой приводит к тому, что его используют в контексте значения.

По сути, из-за оператора запятой тип arr является указателем, а размер VLA не учитывается. Смотрите мой связанный ответ для деталей.

2 голосов
/ 24 августа 2010

Немного объяснений, но я подозреваю, что это какая-то оптимизация компилятора для оператора запятой. Значение операции с запятой - это значение последнего выражения. Поскольку компилятор знает, что sizeof является унарным оператором и представлен операцией с запятой, он не беспокоится о вычислении любого, кроме последнего выражения (независимо от того, было ли последнее ссылкой на VLA или нет).

Я написал несколько тестовых программ (gcc 4.3.3 в Ubuntu 9.04):

$ 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

Это может быть где-то задокументировано, но я не знаю, где искать.

1 голос
/ 24 августа 2010

sizeof оценивает во время компиляции. В C99 для массивов переменной длины он будет ждать до времени выполнения. Отметьте этот ответ на аналогичный вопрос.

0 голосов
/ 24 августа 2010

Компилятор знает размер массива: он явно равен 20. Я не думаю, что sz - это VLA. Попробуйте использовать размер массива в качестве параметра функции, например:

void Function(int size)
{
    int arr[size];
    ...
}

Кстати, чтобы понять, что происходит, рекомендуется прочитать ассемблерный код, созданный компилятором. Проверьте, заменяется ли sizeof константой уже во время компиляции.

...