在setjmp之前用局部变量的地址调用空函数,为什么?
call empty function with address of local variable before setjmp, what for?
看了C库的代码,看不懂是怎么回事:
struct Foo *foo = NULL;
lib_var((void *)&foo);
if (setjmp(get_jmp_buf()) == 0) {
foo = ...;
// other calculation that may cause longjmp
} else {
//something bad happens
drop_if_not_null(foo);
}
其中 lib_var
是具有此类原型的函数 void lib_var(void *);
,
以及单独的 C 文件中的此类实现:
void lib_var(void *variable)
{
// nothing
}
那么 lib_var
函数呢,比如 volatile
在 setjmp() != 0
情况下强制编译器从内存中重新读取变量?
这是未定义的行为吗?因为我确信 LTO 删除了这些完全无用的代码,
LTO 不应将确认行为更改为标准代码。
是的,从标准 C 的角度来看,这是未定义的行为 - 或者至少,foo
的值是不确定的,不能安全地用于任何事情。
C17 (n2176) 7.13.2.1 (3):
All accessible objects have values, and all other components of the abstract machine have state,
as of the time the longjmp function was called, except that the values of objects of automatic storage
duration that are local to the function containing the invocation of the corresponding setjmp macro
that do not have volatile-qualified type and have been changed between the setjmp invocation and
longjmp call are indeterminate.
这正是这里的情况:foo
具有自动存储持续时间并且在调用 setjmp
的函数中是本地的,它不是 volatile
限定的,并且它在setjmp
和 longjmp
.
代码的作者可能认为将 &foo
传递给 lib_var
将确保它是在内存中分配的,而不是在寄存器中,因为编译器无法知道是否lib_var
会修改 foo
,它无法将值 NULL
常量传播到 else
块中。但正如您所说,LTO 或其他各种优化可能会打破这一点。作者可能只打算支持他们知道没有做任何此类事情的特定编译器,或者提供了一些超出标准规定的更强有力的保证,但也有可能他们只是感到困惑。
正确的解决方法是将 foo
声明为 volatile
,即 struct Foo * volatile foo = NULL;
.
看了C库的代码,看不懂是怎么回事:
struct Foo *foo = NULL;
lib_var((void *)&foo);
if (setjmp(get_jmp_buf()) == 0) {
foo = ...;
// other calculation that may cause longjmp
} else {
//something bad happens
drop_if_not_null(foo);
}
其中 lib_var
是具有此类原型的函数 void lib_var(void *);
,
以及单独的 C 文件中的此类实现:
void lib_var(void *variable)
{
// nothing
}
那么 lib_var
函数呢,比如 volatile
在 setjmp() != 0
情况下强制编译器从内存中重新读取变量?
这是未定义的行为吗?因为我确信 LTO 删除了这些完全无用的代码,
LTO 不应将确认行为更改为标准代码。
是的,从标准 C 的角度来看,这是未定义的行为 - 或者至少,foo
的值是不确定的,不能安全地用于任何事情。
C17 (n2176) 7.13.2.1 (3):
All accessible objects have values, and all other components of the abstract machine have state, as of the time the longjmp function was called, except that the values of objects of automatic storage duration that are local to the function containing the invocation of the corresponding setjmp macro that do not have volatile-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate.
这正是这里的情况:foo
具有自动存储持续时间并且在调用 setjmp
的函数中是本地的,它不是 volatile
限定的,并且它在setjmp
和 longjmp
.
代码的作者可能认为将 &foo
传递给 lib_var
将确保它是在内存中分配的,而不是在寄存器中,因为编译器无法知道是否lib_var
会修改 foo
,它无法将值 NULL
常量传播到 else
块中。但正如您所说,LTO 或其他各种优化可能会打破这一点。作者可能只打算支持他们知道没有做任何此类事情的特定编译器,或者提供了一些超出标准规定的更强有力的保证,但也有可能他们只是感到困惑。
正确的解决方法是将 foo
声明为 volatile
,即 struct Foo * volatile foo = NULL;
.