闲着没事儿在书架上找书看,又看到了翻得有些旧的《C专家编程》拿起来又翻了一遍,大二买的书,前后看了四遍,这是第五遍,每次看看都能有一点儿新的收获。
#pragma
是来源来Ada语言的一个编译器指示符,#pragma是由编译器来指定的具体效果,书上记录了一个很意思的关于GNU C 1.3.4版本编译器#pragma指示符的效果:
GNU C 1.3.4编译器在遇到#pragma指示符的时候,首先会尝试运行”hack”游戏,如果失败,会再尝试运行”Rogue”游戏,如果还失败,就继续尝试打开Emacs编辑器并运行”汉诺塔”游戏,最后再失败,编译器才报错。
「Rogue」: Unix上的迷宫探索游戏,具体可参见此Wiki
「Hack」: 地牢探索游戏,具体参见Wiki
几个经常用的#pragma
编译时打印消息
#pragma message("compile message")
屏蔽特定编译警告
1
2微软系的msvc使用方法和GCC的不同
1
2设置内存对齐 #pragma pack(内存对齐值)
1
gcc的pragma文档可以在这里找到。
NUL与NULL
平时用习惯了,真正说一下二个的区别可能并不能说得特别清楚。
NUL
表示ASCII码结束的字符,即是'\0'
的字符名字,就是空字符的意思,但是不要误认为这是C的的一个宏定义,这样写是不正确的:
1 |
|
NULL
表示0,内存的0位置(内存地址较低的位置都是操作系统预留的),表示空指针,即指针没有指向任何内容,指针初始化为空的时候都使用NULL
赋值。
setjmp longjmp
C语言中比goto
更强大的改变控制流的机制,平常很少用,经常忘记用法。
setjmp(jmp_buf j)
是一个宏,调用处就是标记当前的调用环境的上下文,保存当前的调用堆栈,用来调用longjmp
的时候将控制流返回到这里再次执行,第一次调用setjmp
时一定返回0。
longjmp(jmp_buf j, int return_value)
这里的j就是setjmp
时设置jmp_buf
(保证jmp_buf不变),return_value
就是指定控制流返回setjmp
时,setjmp
再调用一遍时返回的值。
这个强大控制流转移机制,可以实现C语言的异常处理,看个简单的例子:
1 |
|
memory_handler
发现pointer是空指针之后重新将控制流程移回setjmp
带着新的返回值1,然后就进入第一个分支对应的处理语句,最终输出nullpointerexception check memory alloc
。
goto
语句只能在同一个函数中跳转到一个指定标签处的代码,而longjmp
可以跨越函数跳转,是C中一个强大的机制。
使用setjmp
时需要注意一点,如果setjmp
不在main
函数中调用而是在其他自定义函数中调用,那一旦这个自定义调用的函数返回,对应记录的调用上下文环境的jmp_buf
也就失效了,longjmp再调用时,就回不到jmp_buf
记录的控制流处了,像下面这个例子,代码不会有任何输出:
1 |
|