我只是想知道是否可以将以下做法视为安全做法:
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);
}
这是假设foo_buf
中的内存在块范围之外仍然有效(并且未更改)。我担心是否存在在块退出时编译器丢弃或覆盖特定于块的内存的情况。我希望在块中而不是在全局范围中进行声明的原因是,在某些平台上,SOME_MACRO()
可以解析为常量,而在其他平台上则可以解析为表达式,因此可以优化if块中的代码。在某些情况下。
答案 0 :(得分:3)
这是假设foo_buf中的内存在块范围之外仍然有效(且不变)
这是一个很大的假设。尝试将内存取消引用到不再在范围内的变量会调用undefined behavior。无法保证内存将包含您认为的内容。
最好在更高范围内定义该缓冲区,使其仍然有效,或者动态分配内存以使其保持有效。
此外,类型不正确:
char * foo_buf[20];
这定义了一个指针数组,而不是一个字符数组。应该是:
char foo_buf[20];
答案 1 :(得分:3)
是UB。
提升char * foo_buf[20];
不会给您带来更糟糕的代码。无论如何,所有函数的本地变量都可能分配在顶部,并且编译器非常有能力消除从未使用过的本地变量。
尝试编译:
#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);
}
,将CONST设置为0或1,然后将UP更改为0和1。
使用gcc,clang或icc移动声明(通过更改UP
),即使在-O0
:https://gcc.godbolt.org/z/z9jnQD上也没有区别。