控制函数用于对C语言程序的标准控制流(如if/else、switch、for等)提供扩展,在头文件assert.h、setjmp.h和signal.h中提供,分别提供表达式断言功能、非本地跳转功能、信号处理功能。
1、assert.h: 提供用于断言的assert宏。程序中若没有定义NDEBUG,则asset(exp)对表达式exp进行断言,若断言为假(即为0),则会调用__assert_fail函数打印一条“断言失败”的消息,并终止程序。若定义了NDEBUG宏,则assert通常为空语句。
- /* ISO C99 Standard: 7.2 诊断 <assert.h> */
- #ifdef _ASSERT_H
- # undef _ASSERT_H
- # undef assert
- # undef __ASSERT_VOID_CAST
- # ifdef __USE_GNU
- # undef assert_perror
- # endif
- #endif /* assert.h */
- #define _ASSERT_H 1
- #include <features.h>
- #if defined __cplusplus && __GNUC_PREREQ (2,95)
- # define __ASSERT_VOID_CAST static_cast<void>
- #else
- # define __ASSERT_VOID_CAST (void)
- #endif
- /* void assert (int expression);
- 如果定义了NDEBUG,什么也不做,如果没有定义,且EXPRESSION为0,则打印一个错误消息,然后终止程序
- */
- #ifdef NDEBUG
- # define assert(expr) (__ASSERT_VOID_CAST (0))
- /* void assert_perror (int errnum);
- 如果定义了NDEBUG,什么也不做。如果没有定义,且ERRNUM为0,则打印对应于错误码ERRNUM的错误消息,
- 然后终止程序 */
- # ifdef __USE_GNU
- # define assert_perror(errnum) (__ASSERT_VOID_CAST (0))
- # endif
- #else /* 没有定义NDEBUG */
- #ifndef _ASSERT_H_DECLS
- #define _ASSERT_H_DECLS
- __BEGIN_DECLS
- /* 这里打印一条“断言失败”的消息,然后终止程序 */
- extern void __assert_fail (__const char *__assertion, __const char *__file,
- unsigned int __line, __const char *__function)
- __THROW __attribute__ ((__noreturn__));
- /* 与上面一样,但打印错误码ERRNUM的错误消息 */
- extern void __assert_perror_fail (int __errnum, __const char *__file,
- unsigned int __line,
- __const char *__function)
- __THROW __attribute__ ((__noreturn__));
- /* 下面的函数在这里并没有使用,但为了与标准兼容,还是需要提供 */
- extern void __assert (const char *__assertion, const char *__file, int __line)
- __THROW __attribute__ ((__noreturn__));
- __END_DECLS
- #endif /* Not _ASSERT_H_DECLS */
- /* 使用上面的函数来定义完整的assert宏 */
- # define assert(expr) /
- ((expr) /
- ? __ASSERT_VOID_CAST (0) /
- : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))
- # ifdef __USE_GNU
- # define assert_perror(errnum) /
- (!(errnum) /
- ? __ASSERT_VOID_CAST (0) /
- : __assert_perror_fail ((errnum), __FILE__, __LINE__, __ASSERT_FUNCTION))
- # endif
- /* 2.4及之后版本的GCC定义了一个魔术变量__PRETTY_FUNCTION__,它包含当前定义的函数名,这在2.6版本之前
- 的G++中打破了。C9x有一个类似的名为__func__的变量,但首选的是GCC的这个变量,因为它重新覆盖了C++中的
- 这个函数名 */
- # if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4)
- # define __ASSERT_FUNCTION __PRETTY_FUNCTION__
- # else
- # if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
- # define __ASSERT_FUNCTION __func__
- # else
- # define __ASSERT_FUNCTION ((__const char *) 0)
- # endif
- # endif
- #endif /* NDEBUG. */
- /* assert.c:assert功能的实现,核心的函数为__assert_fail */
- #include <assert.h>
- #include <libintl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sysdep.h>
- #include <unistd.h>
- extern const char *__progname;
- #ifdef USE_IN_LIBIO
- # include <wchar.h>
- # include <libio/iolibio.h>
- # define fflush(s) INTUSE(_IO_fflush) (s)
- #endif
- /* 本函数当传递一个包含断言表达式的字符串、一个文件名、和一个行号时,在标准
- 错误流上用以下格式打印一条消息:
- a.c:10: foobar: Assertion `a == b' failed.
- 然后通过调用abort来终止程序的执行 */
- #ifdef FATAL_PREPARE_INCLUDE
- # include FATAL_PREPARE_INCLUDE
- #endif
- #undef __assert_fail
- void
- __assert_fail (const char *assertion, const char *file, unsigned int line,
- const char *function)
- {
- char *buf;
- #ifdef FATAL_PREPARE
- FATAL_PREPARE;
- #endif
- /* 把指定格式的消息写入到buf中 */
- if (__asprintf (&buf, _("%s%s%s:%u: %s%sAssertion `%s' failed./n"),
- __progname, __progname[0] ? ": " : "",
- file, line,
- function ? function : "", function ? ": " : "",
- assertion) >= 0)
- {
- (void) __fxprintf (NULL, "%s", buf); /* 打印buf中的消息 */
- (void) fflush (stderr); /* 刷新标准错误流的状态(注意stderr并不缓冲) */
- /* 我们要释放消息缓冲区,因为应用程序可能会捕捉到SIGABRT信号 */
- free (buf);
- }
- else /* 消息写入未成功 */
- {
- /* 至少要打印一个最小的消息 */
- static const char errstr[] = "Unexpected error./n";
- __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);
- }
- abort (); /* 调用abort终止程序 */
- }
- hidden_def(__assert_fail)
- /* assert-perr.c:assert_perror功能是GNU的一个扩展,核心的函数是__assert_perror_fail */
- #include <assert.h>
- #include <libintl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sysdep.h>
- #include <unistd.h>
- extern const char *__progname;
- #ifdef USE_IN_LIBIO
- # include <wchar.h>
- # include <libio/iolibio.h>
- # define fflush(s) INTUSE(_IO_fflush) (s)
- #endif
- /* 本函数当传递一个包含断言表达式的字符串、一个文件名、和一个行号时,在标准
- 错误流上用以下格式打印一条消息:
- a.c:10: foobar: Unexpected error: Computer bought the farm
- 然后通过调用abort来终止程序的执行 */
- #ifdef FATAL_PREPARE_INCLUDE
- # include FATAL_PREPARE_INCLUDE
- #endif
- void
- __assert_perror_fail (int errnum,
- const char *file, unsigned int line,
- const char *function)
- {
- char errbuf[1024];
- char *buf;
- #ifdef FATAL_PREPARE
- FATAL_PREPARE;
- #endif
- /* 把指定格式的消息写入到buf中 */
- if (__asprintf (&buf, _("%s%s%s:%u: %s%sUnexpected error: %s./n"),
- __progname, __progname[0] ? ": " : "",
- file, line,
- function ? function : "", function ? ": " : "",
- __strerror_r (errnum, errbuf, sizeof errbuf)) >= 0)
- {
- (void) __fxprintf (NULL, "%s", buf); /* 打印buf中的消息 */
- (void) fflush (stderr); /* 刷新标准错误流的状态(注意stderr并不缓冲) */
- /* 我们要释放消息缓冲区,因为应用程序可能会捕捉到SIGABRT信号 */
- free (buf);
- }
- else /* 消息写入未成功 */
- {
- /* 至少要打印一个最小的消息 */
- static const char errstr[] = "Unexpected error./n";
- __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);
- }
- abort (); /* 调用abort终止程序 */
- }
- libc_hidden_def (__assert_perror_fail)
- /* __assert.c:__assert函数的实现 */
- /* 我们必须参看原型:没有定义NDEBUG时才会在<assert.h>有__assert的原型 */
- #undef NDEBUG
- #include <assert.h>
- /* 提供__assert函数是为了与标准兼容,它的功能由__assert_fail取代 */
- void
- __assert (const char *assertion, const char *file, int line)
- {
- __assert_fail (assertion, file, line, (const char *) 0);
- }
解释:
(1)GNU还提供了一个扩展assert_perror,功能与assert类似,只不过打印指定的错误码对应的消息,通过__assert_perror_fail函数来实现。另外提供的_assert函数是为了与标准兼容,它的功能由__assert_fail取代。
(2)__assert_fail和__assert_perror_fail函数都是把指定格式的消息写入到buf中,然后打印buf中的消息,并刷新标准错误流的状态,释放消息缓冲区buf,最后要调用abort函数终止程序。
assert宏的原型定义在头文件assert.h中,它的作用是如果宏后面的条件返回假,则终止程序的执行,该宏会调用__assert_fail函数,这个函数内部会先向stderr输出错误信息,然后调用abort函数来终止程序的执行。
一,assert宏的定义
如下:
- # define assert(expr) \
- ((expr) \
- ? __ASSERT_VOID_CAST (0) \
- : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))
__assert_fail函数是一个库导出函数,导出定义如下:
- /* This prints an "Assertion failed" message and aborts. */
- extern void __assert_fail (__const char *__assertion, __const char *__file,
- unsigned int __line, __const char *__function)
- __THROW __attribute__ ((__noreturn__));
二,禁用assert宏
这里要注意一个宏,这个宏很有用,可以禁用assert宏,是如何做到的呢?
- #ifdef NDEBUG
- # define assert(expr) (__ASSERT_VOID_CAST (0))
- /* void assert_perror (int errnum);
- If NDEBUG is defined, do nothing. If not, and ERRNUM is not zero, print an
- error message with the error text for ERRNUM and abort.
- (This is a GNU extension.) */
- # ifdef __USE_GNU
- # define assert_perror(errnum) (__ASSERT_VOID_CAST (0))
- # endif
- #else /* Not NDEBUG. */
- #if defined __cplusplus && __GNUC_PREREQ (2,95)
- # define __ASSERT_VOID_CAST static_cast<void>
- #else
- # define __ASSERT_VOID_CAST (void)
- #endif
三,assert宏注意事项
- 最好使用assert宏检查一个条件,就是不要用&&或者||操作符,这样更容易发现是哪个条件出现问题,在需要的时候,多写几个assert宏。
- 不要使用assert进行变量修改,如assert(k++>10),因为我们可能会禁用这个宏,此时,k++是不会执行的,正如上面我们看到的一样。
- assert不是条件过滤。
- #ifndef ASSERT
- #define ASSERT(x) \
- (void)Assert((x), __FUNCTION__, __FILE__, __LINE__, #x)
- #endif
- inline bool Assert(bool result, const char* function, const char* file,
- int line, const char* expression) {
- if (!result) {
- Log_Assert(function, file, line, expression);
- Break();
- return false;
- }
- return true;
- }
- void Break() {
- #if WIN32
- ::DebugBreak();
- #elif OSX // !WIN32
- ::Debugger();
- #else // !OSX && !WIN32
- #if _DEBUG_HAVE_BACKTRACE
- OutputTrace();
- #endif
- abort();
- #endif // !OSX && !WIN32
- }
2、setjmp.h: 标准库函数setjmp和longjmp实现基本形式的非本地跳转。setjmp用于保存调用者的堆栈环境(被保存在表示跳转缓冲区的jmp_buf型数组ENV中),然后返回0。longjmp用于跳转到保存堆栈环境的地方,并从那里的setjmp调用返回,返回指定的状态码,如果状态码为0则返回1。
- /* ISO C99 Standard: 7.13 非本地跳转 <setjmp.h> */
- #ifndef _SETJMP_H
- #define _SETJMP_H 1
- #include <features.h>
- __BEGIN_DECLS
- #include <bits/setjmp.h> /* 获取__jmp_buf */
- #include <bits/sigset.h> /* 获取__sigset_t */
- /* 调用环境,可能还会附加一个被保存的信号掩码 */
- struct __jmp_buf_tag
- {
- /* 注意:依赖于机器的__sigsetjmp定义假定一个jmp_buf从__jmp_buf开始,后面紧跟着
- __mask_was_saved。不要移动这些成员或者在前面添加其他的成员 */
- __jmp_buf __jmpbuf; /* 调用环境 */
- int __mask_was_saved; /* 保存信号掩码吗? */
- __sigset_t __saved_mask; /* 被保存的信号掩码 */
- };
- __BEGIN_NAMESPACE_STD
- typedef struct __jmp_buf_tag jmp_buf[1]; /* 定义jmp_buf数组 */
- /* 在ENV中保存调用环境,同时也会保存信号掩码,返回0 */
- extern int setjmp (jmp_buf __env) __THROW;
- __END_NAMESPACE_STD
- /* 在ENV中保存调用环境,如果SAVEMASK不为零,则同时也会保存信号掩码。返回0。
- 这是sigsetjmp函数的内部名称 */
- extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __THROW;
- #ifndef __FAVOR_BSD
- /* 在ENV中保存调用环境,不保存信号掩码。返回0 */
- extern int _setjmp (struct __jmp_buf_tag __env[1]) __THROW;
- /* 不保存信号掩码。这与BSD函数'_setjmp'等价 */
- # define setjmp(env) _setjmp (env)
- #else
- /* 在4.3 BSD兼容模式下,setjmp像sigsetjmp(ENV,1)一样来保存信号掩码。我们
- 必须定义一个宏,因为ISO C指出setjmp是完整的 */
- # define setjmp(env) setjmp (env)
- #endif /* Favor BSD. */
- __BEGIN_NAMESPACE_STD
- /* 跳转到保存在ENV中的环境处,使那里的setjmp调用返回VAL,或者返回1(如果VAL为0) */
- extern void longjmp (struct __jmp_buf_tag __env[1], int __val)
- __THROW __attribute__ ((__noreturn__));
- __END_NAMESPACE_STD
- #if defined __USE_BSD || defined __USE_XOPEN
- /* 与上面相同。通常_longjmp与setjmp一起使用,不保存信号掩码。但怎样保存ENV决定了longjmp
- 是否恢复掩码;而_longjmp只是一个别名 */
- extern void _longjmp (struct __jmp_buf_tag __env[1], int __val)
- __THROW __attribute__ ((__noreturn__));
- #endif
- #ifdef __USE_POSIX
- /* 对jmp_buf和sigjmp_buf使用同样的类型。__mask_was_saved标志决定
- longjmp是否将恢复信号掩码 */
- typedef struct __jmp_buf_tag sigjmp_buf[1];
- /* 在ENV中保存调用环境,同时也会保存信号掩码(如果SAVEMASK不为零),返回0 */
- # define sigsetjmp(env, savemask) __sigsetjmp (env, savemask)
- /* 跳转到保存在ENV中的环境处,使那里的sigsetjmp调用返回VAL,或者返回(如果VAL为0)
- 恢复信号掩码(如果那个sigsetjmp保存了它的话)。本函数只是longjmp的一个别名 */
- extern void siglongjmp (sigjmp_buf __env, int __val)
- __THROW __attribute__ ((__noreturn__));
- #endif /* Use POSIX. */
- __END_DECLS
- #endif /* setjmp.h */
- /* setjmp.c:setjmp函数的实现 */
- #include <errno.h>
- #include <setjmp.h>
- /* 在ENV中人嘎当前程序的位置,然后返回0 */
- int
- __libc_sigsetjmp (jmp_buf env, int savemask)
- {
- /* 如果被请求的话,保存信号掩码 */
- __sigjmp_save (env, savemask);
- __set_errno (ENOSYS);
- /* 没有信号失败 */
- return 0;
- }
- weak_alias (__libc_sigsetjmp, __sigsetjmp)
- stub_warning (__sigsetjmp)
- #include <stub-tag.h>
- /* longjmp.c:longjmp函数的实现 */
- #include <stddef.h>
- #include <setjmp.h>
- #include <signal.h>
- /* 在ENV中的相应成员上设置信号掩码,并且跳转到ENV指定的位置处,导致那里的
- setjmp调用返回VAL,或者返回1(如果VAL为0) */
- void
- __libc_siglongjmp (sigjmp_buf env, int val)
- {
- /* 在展开的堆栈结构上需要做清理工作 */
- _longjmp_unwind (env, val);
- if (env[0].__mask_was_saved)
- /* 恢复被保存的掩码 */
- (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
- (sigset_t *) NULL);
- /* 调用依赖于机器的函数来恢复机器状态 */
- __longjmp (env[0].__jmpbuf, val ?: 1);
- }
- strong_alias (__libc_siglongjmp, __libc_longjmp)
- libc_hidden_def (__libc_longjmp)
- weak_alias (__libc_siglongjmp, _longjmp)
- weak_alias (__libc_siglongjmp, longjmp)
- weak_alias (__libc_siglongjmp, siglongjmp)
注意setjmp和longjmp函数都是直接调用内部函数来完成工作的。头文件setjmp.h中的其他部分都是BSD、XOPEN或POSIX方面的扩展。
3、signal.h: 定义了信号原子类型sig_atomic_t、信号处理函数的注册signal、发送信号的函数raise。它包含了bits/signum.h,这个Linux系统的头文件中定义了C标准中的信号及其他一些信号。标准C语言中的信号有SIGINT,SIGILL,SIGABRT,SIGFPE,SIGSEGV,SIGTERM,还要3个特殊的信号SIGERR,SIG_DFL, SIG_IGN,因此标准C语言中总共有9个信号。
signal.h代码如下:
- /* ISO C99 Standard: 7.14 信号处理 <signal.h> */
- #ifndef _SIGNAL_H
- #if !defined __need_sig_atomic_t && !defined __need_sigset_t
- # define _SIGNAL_H
- #endif
- #include <features.h> /* 定义了一些编译选项 */
- __BEGIN_DECLS
- #include <bits/sigset.h> /* 获取__sigset_t和__sig_atomic_t类型 */
- /* 一个可以自动修改的内部类型,它不可能是一个到达运算中间的信号 */
- #if defined __need_sig_atomic_t || defined _SIGNAL_H
- # ifndef __sig_atomic_t_defined
- # define __sig_atomic_t_defined
- __BEGIN_NAMESPACE_STD
- typedef __sig_atomic_t sig_atomic_t; /* 定义信号原子类型 */
- __END_NAMESPACE_STD
- # endif
- # undef __need_sig_atomic_t
- #endif
- #if defined __need_sigset_t || (defined _SIGNAL_H && defined __USE_POSIX)
- # ifndef __sigset_t_defined
- # define __sigset_t_defined
- typedef __sigset_t sigset_t; /* 信号集类型 */
- # endif
- # undef __need_sigset_t
- #endif
- #ifdef _SIGNAL_H
- #include <bits/types.h> /* 定义了一些扩展整数类型 */
- #include <bits/signum.h> /* 定义了C标准中的信号及其他一些信号 */
- #if defined __USE_XOPEN || defined __USE_XOPEN2K
- # ifndef __pid_t_defined
- typedef __pid_t pid_t; /* 进程ID类型 */
- # define __pid_t_defined
- #endif
- #ifdef __USE_XOPEN
- # endif
- # ifndef __uid_t_defined
- typedef __uid_t uid_t; /* 用户ID类型 */
- # define __uid_t_defined
- # endif
- #endif /* Unix98 */
- /* 信号处理函数类型 */
- typedef void (*__sighandler_t) (int);
- /* X/Open的signal定义指定SVID的语义。当需要X/Open兼容性时使用另外一个函数sysv_signal */
- extern __sighandler_t __sysv_signal (int __sig, __sighandler_t __handler)
- __THROW;
- #ifdef __USE_GNU
- extern __sighandler_t sysv_signal (int __sig, __sighandler_t __handler)
- __THROW;
- #endif
- /* 为信号SIG设置信号处理函数HANDLER,返回原来的信号处理函数,出错则返回SIG_ERR
- 默认情况下signal拥有BSD风格的语义 */
- __BEGIN_NAMESPACE_STD
- #ifdef __USE_BSD
- extern __sighandler_t signal (int __sig, __sighandler_t __handler)
- __THROW;
- #else
- /* 确保使用的signal实现是SVID的版本 */
- # ifdef __REDIRECT_NTH
- extern __sighandler_t __REDIRECT_NTH (signal,
- (int __sig, __sighandler_t __handler),
- __sysv_signal);
- # else
- # define signal __sysv_signal
- # endif
- #endif
- __END_NAMESPACE_STD
- #ifdef __USE_XOPEN
- /* X/Open的signal定义与BSD的版本有冲突,因此它们定义定义另外一个函数bsd_singnal */
- extern __sighandler_t bsd_signal (int __sig, __sighandler_t __handler)
- __THROW;
- #endif
- /* 发送信号SIG给PID表示的这个进程。如果PID为0,则发送信号SIG给当前进程组的所有进程。
- 如果PID<-1,则发送SIG给PID表示的进程组中的所有进程 */
- #ifdef __USE_POSIX
- extern int kill (__pid_t __pid, int __sig) __THROW;
- #endif /* Use POSIX. */
- #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
- /* 发送信号SIG给进程组PGRP中的所有进程。如果PGRP为0,则发送信号SIG给
- 当前进程组的所有进程 */
- extern int killpg (__pid_t __pgrp, int __sig) __THROW;
- #endif /* Use BSD || X/Open Unix. */
- __BEGIN_NAMESPACE_STD
- /* 发送信号SIG。例如,发送SIG给你自己 */
- extern int raise (int __sig) __THROW;
- __END_NAMESPACE_STD
- /* 下面都是一些扩展或内部函数 */
- #endif /* signal.h */
- __END_DECLS
- #endif /* not signal.h */
bits/signum.h代码如下:
- /* bits/signum.h:信号码定义,Linux版本 */
- #ifdef _SIGNAL_H
- /* 伪信号函数 */
- #define SIG_ERR ((__sighandler_t) -1) /* 出错时返回 */
- #define SIG_DFL ((__sighandler_t) 0) /* 默认行为 */
- #define SIG_IGN ((__sighandler_t) 1) /* 忽略信号 */
- #ifdef __USE_UNIX98
- # define SIG_HOLD ((__sighandler_t) 2) /* 给信号加保留的掩码 */
- #endif
- /* 信号 */
- #define SIGHUP 1 /* 挂断 (POSIX). */
- #define SIGINT 2 /* 中断 (ANSI). */
- #define SIGQUIT 3 /* 退出 (POSIX). */
- #define SIGILL 4 /* 非法指令 (ANSI). */
- #define SIGTRAP 5 /* 跟踪捕捉 (POSIX). */
- #define SIGABRT 6 /* 异常终止,如调用abort (ANSI). */
- #define SIGIOT 6 /* 图像输出终端(IOT)陷阱 (4.2 BSD). */
- #define SIGBUS 7 /* 总线错误 (4.2 BSD). */
- #define SIGFPE 8 /* 浮点数异常 (ANSI). */
- #define SIGKILL 9 /* 杀死,此信号可解锁 (POSIX). */
- #define SIGUSR1 10 /* 用户定义信号1 (POSIX). */
- #define SIGSEGV 11 /* 段错误,即无效内存访问 (ANSI). */
- #define SIGUSR2 12 /* 用户定义信号2 (POSIX). */
- #define SIGPIPE 13 /* 管道错误 (POSIX). */
- #define SIGALRM 14 /* 时钟警告 (POSIX). */
- #define SIGTERM 15 /* 终止 (ANSI). */
- #define SIGSTKFLT 16 /* 堆栈故障 */
- #define SIGCLD SIGCHLD /* 等同于SIGCHLD (System V). */
- #define SIGCHLD 17 /* 子进程状态已经改变 (POSIX). */
- #define SIGCONT 18 /* 继续 (POSIX). */
- #define SIGSTOP 19 /* 停止,此信号可解锁 (POSIX). */
- #define SIGTSTP 20 /* 键盘发的停止信号 (POSIX). */
- #define SIGTTIN 21 /* 从tty进行后台读操作 (POSIX). */
- #define SIGTTOU 22 /* 后台写入tty (POSIX). */
- #define SIGURG 23 /* socket紧急状态 (4.2 BSD). */
- #define SIGXCPU 24 /* 超出CPU限制 (4.2 BSD). */
- #define SIGXFSZ 25 /* 超出文件大小限制 (4.2 BSD). */
- #define SIGVTALRM 26 /* 时钟虚拟警告 (4.2 BSD). */
- #define SIGPROF 27 /* 时钟Profiling警告 (4.2 BSD). */
- #define SIGWINCH 28 /* 窗口大小改变 (4.3 BSD, Sun). */
- #define SIGPOLL SIGIO /* 可移植的事件发生 (System V). */
- #define SIGIO 29 /* 可以执行I/O (4.2 BSD). */
- #define SIGPWR 30 /* 重启时电源失效 (System V). */
- #define SIGSYS 31 /* 错误的系统调用 */
- #define SIGUNUSED 31
- #define _NSIG 65 /* 最大的信号值+1(包括实时信号) */
- #define SIGRTMIN (__libc_current_sigrtmin ())
- #define SIGRTMAX (__libc_current_sigrtmax ())
- /* 这些是内核的硬限制。这些值不应该在用户级别使用 */
- #define __SIGRTMIN 32
- #define __SIGRTMAX (_NSIG - 1)
- #endif /* <signal.h> included. */
signal函数和raise函数的实现:
- /* signal.c:signal函数的实现 */
- #include <errno.h>
- #include <signal.h>
- /* 为信号SIG设置信号处理函数HANDLER,返回原来的信号处理函数,出错则返回SIG_ERR */
- __sighandler_t
- signal (sig, handler)
- int sig;
- __sighandler_t handler;
- {
- __set_errno (ENOSYS);
- return SIG_ERR;
- }
- weak_alias (signal, ssignal)
- stub_warning (signal)
- stub_warning (ssignal)
- #include <stub-tag.h>
- /* raise.c:raise函数的实现 */
- #include <signal.h>
- #include <errno.h>
- /* 发送SIG */
- int
- raise (sig)
- int sig;
- {
- __set_errno (ENOSYS);
- return -1;
- }
- weak_alias (raise, gsignal)
- stub_warning (raise)
- stub_warning (gsignal)
- #include <stub-tag.h>
注意signal和raise函数并没有做任何特别的实现,只是处理了一下出错时的情况(返回SIG_ERR,即-1)。真正的实现使用Linux中有对应功能的函数,signal直接映射到Linux的ssignal函数,raise直接映射到Linux的gsignal函数。