在阅读MauriceBach的Unix系统设计时,我发现了下面的代码片段。
#include < signal.h>
char *cp;
int callno;
main() {
char *sbrk();
extern catcher();
signal(SIGSEGV, catcher);
cp = sbrk(O);
printf("original brk value %u\n", cp);
for (;;)
*cp++ = 1;
}
catcher(signo) {
int signo;
callno++;
printf("caught sig %d %dth call at addr %u\n", signo, callno, cp);
sbrk(256);
signal(SIGSEGV, catcher);
}
我把主方法中的两个语句搞混了
字符*sbrk();
外部捕手();
我知道
extern
是如何工作的,我也知道sbrk()
是做什么的,但我不明白他们为什么在extern
之前写了catcher()
以及为什么在char*
呼叫之前写了sbrk()
?在编译这段代码时,我在Ubuntu上的gcc-4.8.4上遇到了编译错误,但是在Mac上没有任何错误。为什么会这样?
最佳答案
char *sbrk();
extern catcher();
这些是函数声明,而不是函数调用。您正在阅读的代码是旧式的(pre-ANSI),在随后的(c99或更新的)C标准中,它们不再有效。
您应该在
catcher()
的声明中添加显式返回类型当前隐式声明意味着它有一个int
返回类型但是,信号处理程序的正确签名没有指定返回值当我们添加一个显式的返回类型时,extern
关键字就不再需要了,它可以被删除。sbrk
实际上是在常规头中声明的,因此删除声明并#include <unistd.h>
。但是,sbrk
是BSD(也是SUSv2的一部分),不是标准的C函数,因此在包含#define _BSD_SOURCE
之前,需要用#define _XOPEN_SOURCE=500
或unistd.h
激活声明。Printf
在stdio.h
中声明,因此我们将其包括在内。%u
用于打印unsigned int
。指针应使用%p
格式说明符打印。所以,在代码现代化之后:
#define _BSD_SOURCE
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void catcher();
char *cp;
int callno;
int main(void) {
signal(SIGSEGV, catcher);
cp = sbrk(O); // You sure this should be an O and not a 0?
printf("original brk value %u\n", cp);
for (;;)
*cp++ = 1;
}
void catcher(int signo) {
callno++;
printf("caught sig %d %dth call at addr %p\n", signo, callno, cp);
sbrk(256);
signal(SIGSEGV, catcher);
}
请注意,您应该避免从信号处理程序中调用
printf
。参见例如How to avoid using printf in a signal handler或Signal Handlers and Async-Signal Safety关于c - 在main内部具有函数调用的extern,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43761613/