frasnian
frasnian

Reputation: 2003

C99 VLA size determination and sizeof operator

I wrote the following as part of an answer to a question about sizeof, and its behavior with regard to C99 VLAs:

It would not be difficult to intentionally create a case where the semantics of count_of would effectively differ for a VLA but it might be difficult to create a readable, easily understandable/maintainable, and useful case (I haven't tried to).

After thinking about this, I'm not sure if this statement is actually true. To create a VLA in the first place, the compiler must first determine the amount of space the VLA will require.

For sizeof, we know that

If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant. (6.5.3.4/2)

and although VLA size is obviously a run-time determination, after evaluation (if any, including any side effects) of the size expression for the VLA declarator:

The size of each instance of a variable length array type does not change during its lifetime. Where a size expression is part of the operand of a sizeof operator and changing the value of the size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated. (6.7.5.2/2)

So, given

#define count_of(arr)  (sizeof(arr)/sizeof(arr[0]))

is there any case where the actual effective behavior of a macro such as this could differ for a VLA vs. an array declaration where the array-size expression is a constant expression (i.e. a plain-old pre-C99 fixed-size array)?

Upvotes: 7

Views: 750

Answers (1)

user743382
user743382

Reputation:

The obvious answer is when arr is an expression containing a side effect. If sizeof's argument is evaluated, the side effect takes place. If it isn't evaluated, there is no side effect.

#include <stdio.h>
#define LENGTHOF(arr) (sizeof(arr) / sizeof(*(arr)))
void f() {
  puts("f");
}
int main() {
  const int n = 4;
  int array[n];
  return LENGTHOF(*(f(), &array)) - 4;
}

This is valid in C99, where array is a VLA, and in C++, where n is a constant expression and array is not a VLA. In C99, this prints f. In C++, this does not print anything.

Upvotes: 6

Related Questions