程序员自我修养-2-C实验
一、实验一
1. 实验代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <setjmp.h> void func_bye_1(void) { printf("%s called\n", __func__); } void func_bye_2(void) { printf("%s called\n", __func__); } int test_atexit(void) { int ret; ret = atexit(func_bye_1); if (ret != 0) { fprintf(stderr, "cannot set exit func\n"); return ret; } ret = atexit(func_bye_2); //看起来注册多个是头插法 if (ret != 0) { fprintf(stderr, "cannot set exit func\n"); return ret; } return 0; } int get_sum(int num, ...) { int sum = 0; int *p = &num + 1; //指向下一个参数 printf("%s: &num=%p, p=%p\n", __func__, &num, p); //这是对的,p比&num多4B while (num--) { printf("%s: *p=%d\n", __func__, *p); sum += *p++; } return sum; } void test_indefi_params(void) { int sum = get_sum(3, 10, 20, 30); printf("%s: sum=%d\n", __func__, sum); } void test_crash(void) { char *p = NULL; //x86上exit_group不会被调用了 *p = 1; } #if 0 jmp_buf mark_1; void jump_fun(void) { lonmgjmp(mark_1, 1); } void test_long_jmp(void) { if (setjmp(mark_1) == 1) { printf("world!\n"); } else { printf("hello \n"); jump_fun(); } } #endif int main(int argc, char *argv[]) { int choice; if (argc == 1) { test_crash(); } choice = atoi(argv[1]); if (choice == 1) { test_atexit(); } if (choice == 2) { test_indefi_params(); //x86上测试失败 } if (choice == 2) { //test_long_jmp(); } printf("%s exit\n", __func__); return 0; }
2. 实验结论
2.1 中途崩溃是不会调用exit()的(主动执行完会调用)
//(1)Ubuntu上测试: my_test$ strace ./pp fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0 brk(NULL) = 0x563e1c4d9000 brk(0x563e1c4fa000) = 0x563e1c4fa000 write(1, "main before crash\n", 18main before crash ) = 18 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} --- +++ killed by SIGSEGV (core dumped) +++ Segmentation fault (core dumped) //没有调用 exit_group() //(2)嵌入式设备上测试: prctl(PR_SET_DUMPABLE, SUID_DUMP_USER) = 0 rt_sigaction(SIGTRAP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTART}, {sa_handler=0x72f17fcca8, sa_mask=~[KILL STOP], sa_flags=SA_ONSTACK|SA_RESTART|SA_SIGINFO|0x800}, 8) = 0 getpid() = 19977 gettid() = 19977 rt_tgsigqueueinfo(19977, 19977, SIGTRAP, {si_signo=SIGTRAP, si_code=TRAP_BRKPT, si_pid=2244608512, si_uid=91}) = 0 rt_sigreturn({mask=[RTMIN]}) = 1 --- SIGTRAP {si_signo=SIGTRAP, si_code=TRAP_BRKPT, si_pid=2244608512, si_uid=91} --- +++ killed by SIGTRAP +++ Trap
2.2 atexit() 测试成功, 注册函数的方式是头插法,进程退出时从链表头开始调用。
2.3 函数调用惯例测试失败。
2.4 longjmp测试失败。
posted on 2025-06-02 21:25 Hello-World3 阅读(17) 评论(0) 收藏 举报