块作用域缓冲区在 c 中的块之外是否有效
Is block-scope buffer valid outside of the block in c
我只是想知道以下是否可以被视为安全做法:
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 块内的代码在某些情况下。
This makes the assumption that the memory in foo_buf is still valid (and unchanged) outside of the block scope
这是一个很大的假设。尝试将内存取消引用到不再在范围内的变量会调用 undefined behavior。不能保证内存会包含您认为会包含的内容。
最好在更高的范围内定义该缓冲区,这样它仍然有效,或者动态分配内存以使其保持有效。
另外,类型不正确:
char * foo_buf[20];
这定义了一个指针数组,而不是一个字符数组。应该是:
char foo_buf[20];
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.
我只是想知道以下是否可以被视为安全做法:
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 块内的代码在某些情况下。
This makes the assumption that the memory in foo_buf is still valid (and unchanged) outside of the block scope
这是一个很大的假设。尝试将内存取消引用到不再在范围内的变量会调用 undefined behavior。不能保证内存会包含您认为会包含的内容。
最好在更高的范围内定义该缓冲区,这样它仍然有效,或者动态分配内存以使其保持有效。
另外,类型不正确:
char * foo_buf[20];
这定义了一个指针数组,而不是一个字符数组。应该是:
char foo_buf[20];
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.