块作用域缓冲区在 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.