0

This is C++ code which shows a compiler warning but runs fine. The expected behavior was as below, but:

char sz[] = "Hello World";
char *p;
snprintf(p, 12, sz);
printf("%s", p);

The above code when ran, it crashes as the *p is not allocated. Good.

char sz[] = "Hello World";
char p[0];
snprintf(p, 12, sz);
printf("%s", p);

The above code works fine and will display "Hello World" without any errors. While compiling the above show a compiler warning it is illegal to use [0], but runs fine.

Why it is so?

  • 1
    First of all, please pick *one* language, C and C++ are two very different languages, especially when it come to semantics like this. Other than that, welcome to the wonderful world of [*undefined behavior*](https://en.wikipedia.org/wiki/Undefined_behavior). If you have UB (Undefined Behavior) then all discussion about behavior becomes moot. – Some programmer dude Aug 01 '18 at 05:50
  • 2
    dumb bad luck. [Undefined behaviour](https://en.wikipedia.org/wiki/Undefined_behavior) has, well, behaviour that's undefined. It could do anything, and that includes look like it works. – user4581301 Aug 01 '18 at 05:51
  • 1
    "Runs fine" is a bit optimistic... You are probably overwriting unrelated portions of the stack. Still, it's interesting that in your implementation `p` decays to a pointer to some portion of memory that is decent enough to be overwritten (albeit illegally). Given that all this code falls straightly into undefined behavior and implementation-defined behavior territory, you should specify what compiler you are using. – Matteo Italia Aug 01 '18 at 05:51
  • A good behavior is also a sub-set of un-defined behavior. These kind of code is not recommended. you indeed know here the you are writing to an un-allocated memory. And also compiler is warning you, this is what we can call as assistance from compiler. Whenever you compile a code it should be 0-error and 0-warning, just follow this rule and you will witness very less un-defined behavior. :) – Rizwan Aug 01 '18 at 05:56
  • The dupe link is useful information, but it is not a duplicate, because it fails to clarify (or at least call) the misunderstanding of auto-allocation and the question why it "works" for second code. – Yunnosch Aug 01 '18 at 06:01
  • Thank you all. This issue came across when I was reviewing someone code. The problem is nowadays most of the C++ coding is written by C developers. This is first time I was seeing an array of zero size and want to know why the programmer meant by such a code. – Krishna Prasad P Aug 01 '18 at 06:20

4 Answers4

5

Why it is so?

It is still undefined behavior.

It works in your setup because, by coincidence, the array that holds "Hello World" is adjacent to the variable p in the stack.

Don't rely on such code and don't use them. The behavior of such code can change with compiler changes, using different compiler options, etc.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Not very sure it is because of adjacent memory location, as p is defined after sz and it works fine everytime. – Krishna Prasad P Aug 01 '18 at 06:15
  • 1
    @Krishna, unfortunately, even seemingly sane behavior is under undefined behavior. All I can say is don't rely on such code. – R Sahu Aug 01 '18 at 06:21
1

This

char p[0];

is defining an array of chars of length 0, at a position decided by the linker.
There is no space to print anything into it.

The only difference/improvement compared to

char *p;

Is that the latter does not even have the linker decide on where to put the zero sized space.

You need space to print into. Neither of the two methods provides/reserves any.

Change to

char p[<N>];    

with <N> being a suitably high number to ensure sufficient space, if you can decide on one before compiling.

Use

char* p;
/* ... */
p = malloc(<N>);

if you do not know the suitable size before runtime.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
1

The first snippet, as you expected, invokes undefined behavior by accessing uninitialized pointer (invalid memoory). Good.

The second snippet, is a constraint violation. For an array declaration like p[0], quoting C11, chapter §6.7.6.2, (emphasis mine)

In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. [....]

So, the code is not valid, your compiler should not have produced a binary out of that code. Pump up your compiler warnings.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1
char sz[] = "Hello World";
char *p;
snprintf(p, 12, sz);
printf("%s", p);

correct will get error memory not allocate

char sz[] = "Hello World";
char p[0];
snprintf(p, 12, sz);
printf("%s", p);

some of the compiler allocate size as per string length but mostly we should avoid this and this is compiler dependent issue nothing related to snprintf

eisbehr
  • 12,243
  • 7
  • 38
  • 63
Subodh
  • 40
  • 5
  • 1
    Your answer is not clear to me. I could guess, but I won't. – alk Aug 01 '18 at 08:31
  • @alk The above code works fine and will display "Hello World" without any errors. While compiling the above show a compiler warning it is illegal to use [0], but runs fine. Why it is so? that's what tring to explain some of the compiler will allocate memory as per required length to variable and store data/string into that, pop a warning message :) – Subodh Aug 01 '18 at 10:03