tags:

views:

81

answers:

4

As sizeof operator evaluates operand if it's a VLA so I tried to test it as :

#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); 
}  

I thought that i won't increment as sz is not VLA but j would increment as arr is VLA.
But in the output, none of the i and j incremented.

A: 

Compiler knows the array size: it is obviously 20. I don't think that sz is VLA. Try to use use array size as function parameter, for eaxmple:

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

BTW, to understand what happens, it is recommended to read Assembly code produced by compiler. Check whether sizeof is replaced by a constant already at compile time.

Alex Farber
The compiler does know the array size in this case, but it is techincally a VLA because sz is a variable, not a constant. Even if it were a constant (const int sz=20;), that doesn't make the array any less a VLA (for all that it will always have the same size).
Jonathan Leffler
+1  A: 

sizeof evaluates at compile time. In C99 for variable length arrays it will wait until runtime. Check this answer to a similar question.

celavek
+4  A: 

Quoting my answer to another question:

The "conversion" is due to the subtraction operator. You can see a similar, and perhaps more surprising, result with the comma operator:

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

will also print sizeof(int *), because of the comma operator resulting in a getting used in a value context.

Basically, due to the comma operator, the type of arr is a pointer, and the size of the VLA doesn't come into the picture. See my linked answer for details.

Alok
Ok..I understand..So is there a way that I can utilize this fact "sizeof evaluates operand if it is a vLA" to increment or modify some other operand as I was trying to do here ?
Happy Mittal
@Happy: I wouldn't call that "utilize", it's more like "abusing the `sizeof` operator". What exactly are you trying to do?
Alok
+2  A: 

Not much of an explanation but I suspect it's some compiler optimization for the comma operator. The value of a comma operation is the value of the last expression. With the compiler knowing sizeof is a unary operator and presented with a comma operation, it doesn't bother to evaluate any but the last expression (regardless whether the last was a reference to a VLA or not).

I wrote some test programs (gcc 4.3.3 on 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

Note the absences of the string literals and the second printf() call.

$ cat test-alt.c # without 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

It may be documented somewhere but I wouldn't know where to look.

Jeff M