C标准库源码解剖(9):控制函数assert.h, setjmp.h和signal.h

2023-05-16

    控制函数用于对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函数终止程序。
    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函数。

转载于:https://my.oschina.net/abcijkxyz/blog/722816

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C标准库源码解剖(9):控制函数assert.h, setjmp.h和signal.h 的相关文章

  • 如何在不添加参数的情况下对基于时间的函数进行单元测试

    我创建了一个函数 该函数返回距离下次出现该时间还剩下的秒数 但我在为其编写单元测试时遇到了问题 人们如何测试这种类型的调用函数datetime now in it 添加另一个参数 current time 仅仅测试它似乎是错误的 因为它改变
  • 为什么junit中的assertEquals和assertSame对于同一个类的两个实例返回相同的结果?

    根据文件 assertEquals 断言两个对象相等 assertSame 断言两个对象引用同一个对象 所以我期待如果我有像下面这样的课程 class SomeClass then SomeClass someClass1 new Some
  • 使用 LifecycleCallbacks 时找不到该文件

    我有问题form validation in symfony2 就我而言 form gt isValid 命令结果为The file could not be found 即使我在填写表格时提供了文件 另外调试setFile函数于docum
  • Groovy 'assert':如何显示值?

    如何在 groovy 中显示一个值 无论它是 true 还是 false 我使用 Eclipse 作为我的 IDE assert 4 2 3 6 14 integers only 而且我不太理解 Groovy 中的 断言 它像 Java 中
  • *(int*)NULL = 1 导致线程崩溃;有问题吗?

    我在多线程 C 应用程序中发现了这个 作者评论说它用于在自定义断言函数中造成线程崩溃 GCC 对此没有问题 但 clang 发出以下警告 note consider using builtin trap or qualifying poin
  • [C++ 编译时断言]:如果不满足某些条件,我们可以抛出编译错误吗?

    我写了一个函数 template
  • 在ABAP中使用自定义消息引发异常

    我正在编写一个通过 RFC 调用的函数 我想找到最简单的方法来在 ABAP 中使用自定义消息引发异常 如果这可以尽可能短地完成 并且可以在一行上完成 那就太好了 我希望它用于调试 而不是用于运行生产代码 背景 过去我使用Python编程语言
  • Python:断言变量是实例方法?

    如何检查变量是否是实例方法 我正在使用Python 2 5 像这样的事情 class Test def method self pass assert is instance method Test method inspect ismet
  • 断言两个 java bean 是等价的

    这个问题 https stackoverflow com questions 472626 how to generically compare entire java beans很接近 但仍然不是我想要的 我想以通用的方式断言两个 bea
  • setjmp.h 中定义的 C 语言非本地跳转如何工作?

    The C语言参考手册 附录B描述了两个函数setjmp and longjmp对于所谓的东西非局部跳转 除了基本的了解之外setjmp保存状态信息 longjmp 恢复state 我一直无法理解此功能的确切流程和用例 那么 这个功能到底有
  • 如何 PHPUnit 断言函数

    我想知道如何验证 类 是否具有函数 assertClassHasAttribute 不起作用 这是正常的 因为函数不是属性 当 PHPUnit 没有提供断言方法时 我要么创建它 要么使用带有详细消息的较低级别断言之一 this gt ass
  • .NET 生产代码中的“Assert”语句

    离开是否明智Trace Assert and Debug Assert代码中的语句是否 稳定 并且已移至测试和生产环境中 如果是这样 这些断言语句有何帮助 让 Guard 类等检查异常情况并适当引发异常还不够吗 调试断言 http msdn
  • 2 个 JUnit Assert 类之间的差异

    JUnit 框架包含 2Assert类 显然在不同的包中 和每个类的方法看起来非常相似 有人能解释这是为什么吗 我指的课程是 junit framework Assert http junit org junit javadoc 4 5 j
  • 如何在运行时检测某些编译器选项(如断言)是否设置为 ON?

    Delphi 中检查断言是否有效的条件是什么 当断言在代码中不活动时 我希望能够做一些事情来抑制有关未使用变量的提示 例如 procedure Whatever var v Integer begin v DoSomething Asser
  • NUnit 与 Debug.Assert 冲突

    我正在使用 NUnit 为我的同事编写的库编写单元测试 他的库包含大量在无效输入时触发的 Debug Asserts 当我编写单元测试并向他的库提供无效输入时 他的 Debug Assert 会弹出一个消息框 抱怨输入错误 我觉得他的库对无
  • 如何在 java 类方法或构造函数中插入前提条件?

    这是我正在上的 Java 课程 本书提到了前置条件和后置条件 但没有给出任何如何对其进行编码的示例 它继续讨论断言 我已经把它记下来了 但是我正在做的作业特别指出插入前提条件并用断言测试前提条件 任何帮助都会很棒 像 Eiffel 这样的语
  • 如何在c中断言两个类型相等?

    在 C 中如何断言两种类型相等 在 C 中 我会使用 std is same 但搜索 StackOverflow 和其他地方似乎只能给出 C 和 C 的结果 在C中没有办法做到这一点吗 请注意 这不是询问变量是否具有某种类型 而是询问两个类
  • MySQL 中的断言

    我有一个针对大型数据库运行的 SQL 脚本 我想在开始时提出几个简单的查询 作为健全性检查 有没有办法在MySQL中写断言 或者任何类型的 选择 如果它与该值不匹配 则中止整个脚本 一些疯狂的代码 要点是 SET可能会引发 mysql 变量
  • SOAPUI 方括号括住我的实际结果,导致断言失败

    我正在编写一个 Groovy 脚本断言 该断言根据 SOAP 响应中包含的值来验证先前 JDBC 响应步骤中的值 当我运行脚本时 我可以看到两个值返回相同 但实际结果值 来自 SOAP 响应 被方括号括起来 这反过来又使断言失败 我猜这与一
  • Python 中的“断言”有什么用?

    什么是assert意思是 它是如何使用的 The assert语句几乎存在于所有编程语言中 它有两个主要用途 它有助于在程序早期发现问题 原因明确 而不是等到其他操作失败时才发现问题 例如 Python 中的类型错误在实际引发错误之前可能会

随机推荐