簡體   English   中英

在main內部具有函數調用的extern

[英]extern with function call inside main

在閱讀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); 
}

我對主方法中的兩個語句感到困惑

char * sbrk();

extern catcher();

我了解extern工作原理,也了解sbrk()作用,但我不明白為什么他們在catcher()之前寫了extern ,又為什么在sbrk()調用之前寫了char*

編譯此代碼時,我在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函數,因此在包含unistd.h之前,需要使用#define _BSD_SOURCE#define _XOPEN_SOURCE=500激活聲明。

Printfstdio.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 例如,請參見如何避免在信號處理程序中使用printf信號處理程序和異步信號安全性

除了@KlasLindbäck的答案以外,在當前的C和POSIX標准下,此代碼還存在其他問題:

#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()

sbrk()已從POSIX標准中刪除。 直接使用不再安全。 在Linux手冊頁中

避免使用brk()sbrk()malloc(3)內存分配包是可移植且舒適的內存分配方式。

為什么? 因為許多C庫函數經常在內部使用malloc() / calloc() / realloc() / ...,並且在同一進程中混合使用malloc()brk() / sbrk()是不安全的 malloc()實現經常在內部使用brk() / sbrk() ,因此在您自己的代碼中使用sbrk()可能會破壞您的堆。

不要使用signal()

signal()存在嚴重問題 這根本不一致。 請改用sigaction()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM