ctype.h

Assert

风中纸页 posted @ 2008年9月05日 22:41 in C标准库学习笔记 , 3409 阅读
转贴请保留本文作者及文章地址

 

/* 以上为活跃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 */



问题:

1,一般情况下宏都是要大写的,但为什么要把一些宏要做成小写呢? 难道就仅仅是为了“看起来”
像是一个函数而已么?

 

  • 无匹配
Connor Tufnell 说:
2018年7月27日 12:46

As you keep your followers updated from latest wen development methods with share of coding on here this is very nice buddy. Instead copying of works you can also buy essays online uk on reasonable prices without waste of time.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter