/* 以上为活跃c.c.l.c组内容乱写,版权所有,谢绝转载 */
/* ++ Assert.h */
/* 去掉头文件说明 */
/*
* ISO C99 Standard: 7.2 Diagnostics <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);
If NDEBUG is defined, do nothing.
If not, and EXPRESSION is zero, print an error message and abort. */
#ifdef NDEBUG
/* 为了当expr != 0 ,不输出任何内容 */
# 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
/* 到这里可以看出如果定义了NDEBUG那么assert(expr) 这个宏就无效了 */
#else /* Not NDEBUG. */
/* #ifdef __cplusplus
* # define __BEGIN_DECLS extern "C" {
* # define __END_DECLS }
* #else
* # define __BEGIN_DECLS
* # define __END_DECLS
* #endif
* 这个宏的目的就是给C++编译器看的,下面是C代码而不是C++的。实现如上
*/
__BEGIN_DECLS
/* 这里定义了两个宏, 这个assert是兼容标准C库,在assert.c会看到
* __assert_fail()这个函数的实现。
*/
extern void __assert_fail (__const char *__assertion, __const char *__file,
unsigned int __line, __const char *__function)
__THROW __attribute__ ((__noreturn__));
/* 给GNU扩展用的 */
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__));
/* 和上面的那个__BEGIN_DECLS对应 */
__END_DECLS
/* 这个是glibc的实现的宏 */
/* __STRING(expr)实现如下:
* #define __STRING(x) #x
* 可以看到这个宏利用了宏定义的# 来达到传入表达式字符串的目的
*/
/* __ASSERT_FUNCTION实现如下:
* # 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
* 可以看到这个宏的目的就是替代函数名
* 但__STDC_VERSION__ >= 199901L是啥意思?
*/
/* 如下这种实现方式是规范要求
* 规范的例子如下:
* #undef assert
* #ifdef NDEBUG
* #define assert(ignore) ((void)0) 10
* #else
* extern void _ _gripe(char *_Expr, char *_File,
* int _Line, const char *_Func);
* #define assert(expr) \
* ((expr) ? (void)0 :\ 15
* _ _gripe(#expr, _ _FILE_ _,_ _LINE_ _,_ _func_ _))
* #endif
从这个例子中我们也可以看到glibc的实现和规范的参考设计有哪些不同
*/
# define assert(expr) \
((expr) \
? __ASSERT_VOID_CAST (0) \
: __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))
/* 下面这个是GNU扩展用的。 */
# ifdef __USE_GNU
# define assert_perror(errnum) \
(!(errnum) \
? __ASSERT_VOID_CAST (0) \
: __assert_perror_fail ((errnum), __FILE__, __LINE__, __ASSERT_FUNCTION))
# endif
/* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__'
which contains the name of the function currently being defined.
This is broken in G++ before version 2.6.
C9x has a similar variable called __func__, but prefer the GCC one since
it demangles C++ function names. */
/* #if defined __GNUC__ && defined __GNUC_MINOR__
* # define __GNUC_PREREQ(maj, min) \
* ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
* #else
* # define __GNUC_PREREQ(maj, min) 0
* #endif
* __GNUC_PREREQ就是一个方便看版本的宏,实现如上
*/
# 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.h*/
/* 下面就是源文件 */
/* ++ Assert.c */
/* Copyright (C) 1991,1994-1996,1998,2001,2002,2005
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#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
/* This function, when passed a string containing an asserted
expression, a filename, and a line number, prints a message
on the standard error stream of the form:
a.c:10: foobar: Assertion `a == b' failed.
It then aborts program execution via a call to `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
/* __asprintf 的用法可以参考vasprintf用法基本相同:
* 其实现在Vasprintf.c中
*/
if (__asprintf (&buf, _("%s%s%s:%u: %s%sAssertion `%s' failed.\n"),
__progname, __progname[0] ? ": " : "",
file, line,
function ? function : "", function ? ": " : "",
assertion) >= 0)
{
/* Print the message. */
/* __fxprintf的用法可以参考vfprintf,用法基本相同: */
(void) __fxprintf (NULL, "%s", buf);
/* 由于输出为标准错误输出,需要及时把错误刷上去 */
(void) fflush (stderr);
/* We have to free the buffer since the application might catch the
SIGABRT. */
/* 这里为什么必须要马上把这个buffer释放掉呢? */
free (buf);
}
else
{
/* At least print a minimal message. */
/* 对于这种特殊的情况,那么需要特殊处理。
* 那么这里就涉及到STDERR_FILENO和stderr有什么区别呢?
* STDERR_FILENO是标准文件输出,无缓冲IO,相当于直接调用系统调用,
* 这也就解释了为什么要用_libc_write这个函数了。
*/
static const char errstr[] = "Unexpected error.\n";
__libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);
}
/* 为了程序终止的不同可能性,规范要求以abort来结束。
这里使用的还是库函数,规范要求的abort个人理解应当是系统调用,那么我们在读到
库函数abort的时候要留意一下是否有关于系统调用的实现规范。
Abort库函数会发一个SIGABRT的异常信号,在库函数中属于环境函数
*/
abort ();
}
hidden_def(__assert_fail)
/* -- Assert.c */