[英]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
激活聲明。
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
。 例如,請參見如何避免在信號處理程序中使用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.