0

In standard C and C++ the address of an array is the array itself, and sizeof returns the size of the array, not the pointer. However, does gcc's extension of dynamically-sized arrays offer the same guarantee?

I tried this simple code:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char ** argv)
{
    char foo[200];
    char bar[atoi(argv[1])];
    char *wibble = foo;

    printf("%p, %p, %lu, %p, %p, %lu, %p, %p, %lu\n",
           foo, &foo, sizeof(foo), bar, &bar, sizeof(bar), wibble, &wibble, sizeof(wibble));

    return 0;
}

The output is as I hoped, indicating equivalence:

0x7ffc7dd132e0, 0x7ffc7dd132e0, 200, 0x7ffc7dd131e0, 0x7ffc7dd131e0, 200, 0x7ffc7dd132e0, 0x7ffc7dd132c8, 8

However, is this equivalence guaranteed by gcc? Are there any times where using a dynamically-sized instead of a statically-sized array will result in different program behaviour?

※ Note I'm interested in if it works, not how to write it better using std::vector, etc

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Ken Y-N
  • 14,644
  • 21
  • 71
  • 114
  • 3
    Why would you expect a non-standard language extension to provide strict guarantees on this behavior? It's hard to "language lawyer" things that aren't part of the language. – ShadowRanger Jan 17 '20 at 03:57
  • "*The output is as I hoped, indicating equivalence:*" Is it? What does the compiled code look like? Does it change if you pass different numbers as arguments? What happens if you use `sizeof(bar)` in a constant expression? – Nicol Bolas Jan 17 '20 at 04:09
  • @NicolBolas Yes, using `sizeof(bar)` in a constant expression is obviously going to be problematic; that's why I'm asking the question! @ShadowRanger I would hope that the developers thought through the issues, not just slapped in a hack to support the declaration. – Ken Y-N Jan 17 '20 at 04:12
  • @KenY-N: If you know that they're not equivalent... why are you asking if they're equivalent? – Nicol Bolas Jan 17 '20 at 04:14
  • @NicolBolas I only realised they are not equivalent when you posed your question! Where else might they differ? – Ken Y-N Jan 17 '20 at 04:16

1 Answers1

1

Straight from the ISO C99 doc, page 80:

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. 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.

So the answer to your first question is that it's guaranteed by the C99 standard, which gcc presumably follows.

As for whether there are times it'll behave differently from a statically sized array well...not if you're using them sanely.

While I can't find record of this in ISO C99, it appears that gcc always puts a VLA on the stack - which makes sense because it's essentially an alloca(), and is intended to go out of scope at the end of the block. Used sanely, there should never be any difference between how a dynamically sized array behaves and how a statically sized array behaves. Used insanely however, yes there could be extreme corner cases for exploitation (or other hacky) behavior where a person doing exploitation might be happy to discover you're using one over the other.

Regardless, you can probably feel comfortable using whichever one you feel comfortable with. Usually, (for one or two reasons of varying justifiability) programmers prefer malloc over stack allocations.

Indiana Kernick
  • 5,041
  • 2
  • 20
  • 50
Roguebantha
  • 814
  • 4
  • 19
  • Ahh, I had forgotten that [VLAs are official C from C99 onwards (but not C++)](https://stackoverflow.com/q/1887097/1270789), so there has to be official language for their validity, and I suppose for C++ the `g++` people decided they cannot be used (for example (just guessing here!)) in templates when the size cannot be determined at compile time, or similar. – Ken Y-N Jan 17 '20 at 05:21