Can the following can be considered safe practice?
void some_func(void) {
const char * foo;
if (SOME_MACRO()) {
char * foo_buf[20];
snprintf(foo_buf,sizeof(foo_buf),"blah_%d",some_global);
foo = foo_buf;
} else {
foo = "some constant string";
}
// do a bunch of other stuff here...
printf("%s\n", foo);
}
This makes the assumption that the memory in foo_buf
is still valid (and unchanged) outside of the block scope. I'm concerned if there are any situations where the compiler discards or overwrites block specific memory when the block has exited.
The reason I'd like the declaration in the block rather than in global scope is that on some platforms, SOME_MACRO()
would resolve to a constant, in others, to an expression, so the code inside the if block can be optimized out in some cases.
It's UB.
Lifting char * foo_buf[20];
up shouldn't give you worse code. All the function's locals are likely to be allocated at the top anyway and compilers are quite well capable of eliminating locals that get never used.
Try compiling:
#define UP 0
#define CONST 1
#include <stdio.h>
#if CONST
#define SOME_MACRO() 0
#else
int SOME_MACRO(void);
#endif
int some_global;
void some_func(void) {
const char * foo;
#if UP
char foo_buf[20]; // Fixed from char *foo_buf[20];
#endif
if (SOME_MACRO()) {
#if !UP
char foo_buf[20]; //fixed from char *foo_buf[20];
#endif
snprintf(foo_buf,sizeof(foo_buf),"blah_%d",some_global);
foo = foo_buf;
} else {
foo = "some constant string";
}
// Do a bunch of other stuff here...
printf("%s\n", foo);
}
with with CONST set to either 0 or 1 and then changing UP to between 0 and 1.
With GCC, Clang, or Intel C++ Compiler, moving the declaration (by changing UP
) doesn't make any difference, even at -O0: See this code at Compiler Explorer.