extern函数调用main

Nul*_*ter 1 c unix

在阅读Maurice Bach的Unix System Design时,我遇到了下面的代码片段.

#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); 
}
Run Code Online (Sandbox Code Playgroud)

我对main方法中的两个语句感到困惑

char*sbrk();

extern catcher();

我理解是如何extern工作的,我也知道什么sbrk()做但我无法理解为什么他们extern之前写过catcher(),为什么char*sbrk()打电话之前写的?

在编译此代码时,我在Ubuntu上的gcc-4.8.4上遇到了编译错误,但代码在Mac中没有任何错误编译.为什么会这样?

Kla*_*äck 5

char *sbrk();
extern catcher();
Run Code Online (Sandbox Code Playgroud)

这些是函数声明,而不是函数调用.您正在阅读的代码是旧样式(ANSI之前的版本),在随后的(c99或更新版本)C标准中,它们不再有效.

您应该在声明中添加显式返回类型catcher().当前的隐式声明意味着它具有int返回类型.但是,信号处理程序的正确签名不指定返回值.当我们添加显式返回类型时,extern不再需要关键字,可以删除它.

sbrk实际上是在常规标题中声明,所以删除声明和#include <unistd.h>.但是,sbrkBSD(和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); 
}
Run Code Online (Sandbox Code Playgroud)

请注意,您应该避免printf在信号处理程序内进行调用.请参阅示例如何避免在信号处理程序信号处理程序和异步信号安全中使用printf