鉴于以下代码:
typedef struct {int a;} test_t;
arbitrary_t test_dosomething(test_t* test) {
if (test == NULL) {
//options:
//1. print an error and let it crash
//e.g. fprintf(stderr, "null ref at %s:%u", __FILE__, __LINE__);
//2. stop the world
//e.g. exit(1);
//3. return (i.e. function does nothing)
//4. attempt to re-init test
}
printf("%d", test->a); //do something w/ test
}
如果test
永远是NULL
,我想得到一个编译器错误,但我想这在C中是不可能的。因为我需要在运行时进行空检查,哪种选项是最合适的方式处理它?</ p>
答案 0 :(得分:7)
如果您不希望使用空指针调用该函数(即,指针不为null是调用函数的前提条件),则可以在函数顶部使用断言:
assert(test != NULL);
这可以帮助您在调试时查找代码中使用空指针调用函数的位置。
答案 1 :(得分:4)
我们真的不能断然回答这个问题。它在很大程度上取决于软件将用于什么。如果它提供辐射,您会希望它打印错误exit(1);
。如果您正在编写业务应用程序,则可能需要记录错误并返回。 这完全取决于上下文。
答案 2 :(得分:1)
我会在函数的开头使用一个断言:
arbitrary_t test_dosomething(test_t* test) {
assert(test != NULL);
printf("%d", test->a); //do something w/ test
}
您不会收到编译器错误。但是在开发(调试)时,程序将停止并指向代码中的特定assert
。
答案 3 :(得分:1)
使用setjmp。
http://en.wikipedia.org/wiki/Setjmp.h
http://aszt.inf.elte.hu/~gsd/halado_cpp/ch02s03.html
#include <setjmp.h>
#include <stdio.h>
jmp_buf x;
void f()
{
longjmp(x,5); // throw 5;
}
int main()
{
// output of this program is 5.
int i = 0;
if ( (i = setjmp(x)) == 0 )// try{
{
f();
} // } --> end of try{
else // catch(i){
{
switch( i )
{
case 1:
case 2:
default: fprintf( stdout, "error code = %d\n", i); break;
}
} // } --> end of catch(i){
return 0;
}
答案 4 :(得分:0)
这实际上取决于您的用例。如果您有交互式应用程序,请提示并让用户更正输入。如果是服务器进程,则可能需要进行日志记录。如果错误将使您的程序向南移动,则执行断言。
答案 5 :(得分:0)
如果test为NULL,它是一个运行时值,并且它甚至可能依赖于用户输入,编译器也无法知道它的值。
要避免使用NULL值调用函数,请使用assert:
assert(test != NULL);
这意味着:我的代码无法将NULL作为输入处理。它会在运行时中止。
你的函数应该返回arbitrary_t并且它没有返回任何东西。
你也可以在你现在没有使用的返回值中将错误发送回调用者,例如返回一个arbitrary_t *,如果无法分配则为NULL(这将是这种情况)如果test_t是NUL)。调用者需要测试它。
答案 6 :(得分:0)
显然(我最近在网上搜索了“C静态断言”),C ++ 0x有一个static_assert,而C人正在谈论类似的东西以及下一个C标准。当然,这意味着C中目前没有标准的“静态断言”。
有人建议使用布尔表达式定义枚举或结构的C预处理器宏,如果条件表达式失败,则使用?:
运算符生成非法的枚举/结构定义。 (上面的网络搜索列出了许多这样的宏定义。)
就个人而言,无论如何我总是使用gcc,我只是声明了
这样的功能foo_t function(moo_t *moo) __attribute__(( nonnull(1) ));
并且因此如果我不小心调用参数设置为-Wnonnull
的函数,编译器会给我一个警告(-Wall
,包含在NULL
中)。
答案 7 :(得分:0)
我只能回应上述内容 - 这取决于你的申请。
一个好的经验法则是尽早发现错误。这通常使得查找和纠正问题变得更容易,更快速和更便宜。理想情况下,你会在设计时抓住这个。正如您所指出的那样,您无法在编译时捕获它(除非切换到像Eiffel这样的“按合同设计”语言),因此您可以在运行时捕获它。
然后......这取决于......
如果它是一个桌面应用程序,那么可能是一个巨大的对话框和退出是修复它的最快方法,如果它导致某人报告错误。如果可以,也可以向开发人员发送电子邮件(例如,如果它是内部应用程序)。
如果它是任务关键型或生命关键型,您可能只需重新启动应用程序(这是嵌入式系统中的一般方法)。
无论您做出什么决定,都要尽可能多地收集有关问题的信息。例如,您可以滚动您的赢取的宏来包装ASSERT,其中添加文件和 LINE )。
我使用以下内容:
#ifdef TESTING
#define ASSERT_MSG(subsystem, message, condition) if (!(condition)) {printf("Assert failed: \"%s\" at line %d in file \"%s\"\n", message, __LINE__, __FILE__); fflush(stdout); abort();}
/* we can also use this, which prints of the failed condition as its message */
#define ASSERT_CONDITION(subsystem, condition) if (!(condition)) {printf("Assert failed: \%s\" at line %d in file \%s\"\n", #condition, __LINE__, __FILE__); fflush(stdout); abort();}
#else
#define ASSERT_MSG(subsystem, message, condition) if (!condition) DebugTrace(FATAL, subsystem, __FILE__, __LINE__, "%s", message);
#define ASSERT_CONDITION(subsystem, condition) if (!(condition)) DebugTrace(FATAL, subsystem, __FILE__, __LINE__, "%s", #condition);
#endif