[英]Does setjmp literally save the state of the program?
所以,如果我要 malloc 500 字節,然后使用setjmp
保存 state,然后釋放 500 字節,然后是longjmp
,我可以訪問這 500 字節嗎? 例如:
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
jmp_buf buf;
struct str {
char s[200];
int a;
};
int main() {
struct *str = (struct str *)malloc(sizeof(str));
(*str).s = "the string";
(*str).a = 31;
setjmp(buf);
printf("%s %d\n", (*str).s, (*str).a);
free(str);
longjmp(buf, 1);
printf("%s %d\n", (*str).s, (*str).a);
return 0;
}
第二個printf
的 output 是什么? 另外, longjmp?
我看到有些人使用大整數作為第二個參數。
setjmp
是字面上保存程序的state嗎?
不, setjmp()
會保存一些 CPU 寄存器值以及一些上下文,以允許程序在一組非常嚴格的條件下在同一位置恢復執行。
請注意,您沒有為struct str
分配足夠的 memory :您傳遞了sizeof(str)
,這是str
指針的大小。 你應該這樣寫:
struct *str = malloc(sizeof(*str));
此外,您不能使用賦值來初始化str->s
,您應該將str
成員定義為const char *
而不是數組。
所以,如果我要 malloc 500 字節,然后使用
setjmp
保存 state,然后釋放 500 字節,然后是longjmp
,我可以訪問這 500 字節嗎?
不,您的程序具有未定義的行為,因為由malloc
分配並由str
指向的 memory 塊已被釋放,因此不能再取消引用str
。
請注意, main
function 中的最后 2 條語句永遠不會執行,因為longjmp()
沒有返回,它使程序在setjmp()
返回的地方恢復執行,並使setjmp
返回傳遞給longjmp()
(如果為此參數傳遞0
,則值為1
)。
這是用於說明的修改版本:
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
jmp_buf buf;
struct str {
const char *s;
int a;
};
int main() {
struct str *str = malloc(sizeof(*str));
str->s = "the string";
str->a = 31;
int res = setjmp(buf);
if (res == 0) {
printf("res: %d, str: %p, s: %s, a: %d\n",
res, (void *)str, str->s, str->a);
free(str);
str = NULL;
printf("str: %p\n", (void *)str);
longjmp(buf, 0);
} else {
printf("res: %d, str: %p\n", res, (void *)str);
if (res < 10)
longjmp(buf, res + 1);
}
return 0;
}
Output(編譯優化):
res: 0, str: 0x7fe44de00000, s: the string, a: 31
str: 0x0
res: 1, str: 0x7fe44de00000
res: 2, str: 0x7fe44de00000
res: 3, str: 0x7fe44de00000
res: 4, str: 0x7fe44de00000
res: 5, str: 0x7fe44de00000
res: 6, str: 0x7fe44de00000
res: 7, str: 0x7fe44de00000
res: 8, str: 0x7fe44de00000
res: 9, str: 0x7fe44de00000
res: 10, str: 0x7fe44de00000
Output(用-O0
編譯):
res: 0, str: 0x7ff4885000e0, s: the string, a: 31
str: 0x0
res: 1, str: 0x0
res: 2, str: 0x0
res: 3, str: 0x0
res: 4, str: 0x0
res: 5, str: 0x0
res: 6, str: 0x0
res: 7, str: 0x0
res: 8, str: 0x0
res: 9, str: 0x0
res: 10, str: 0x0
如您所見, setjmp()
保留的內容很難預測,因此在程序員非常了解編譯器行為且僅用於非常特定的需求的情況下,必須格外小心地使用此 function。
它模糊地指定了setjmp
到底存儲了什么,標准只是說:
調用
setjmp
宏的環境包含足以調用longjmp
function 以將執行返回到正確塊和調用該塊的信息,如果它是遞歸調用的話。 它不包括浮點狀態標志、打開文件或抽象機的任何其他組件的 state。
在實踐中,這可能意味着:程序計數器、堆棧指針、調用約定中涉及的寄存器、基本條件代碼寄存器。 它不包括堆,因為它排序在“抽象機的任何其他組件”之下,而且因為常識告訴我們將整個堆存儲在堆棧上是沒有意義的。
至於您的代碼示例,它是亂碼偽代碼,它以未定義的行為方式使用setjmp
- 使用該 function 的任何代碼都必須始終檢查結果。
一般來說,這些功能是有史以來最糟糕的意大利面條式編程恐怖,應該只用於調試程序流目的,絕不用於生產代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.