Reputation: 2888
Given the code below:
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
}
I want to get a compiler error if test
is ever NULL
, but I guess that's not possible in C. Since I need to do null checking at runtime, what option is the most proper way to handle it?
Upvotes: 6
Views: 1466
Reputation: 13779
Use 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;
}
Upvotes: 2
Reputation: 40205
I can only echo the above - it depends on your application.
A good rule of thumb is to detect an error as early as possible. This generally makes it easier, quicker and cheaper to find and correct the problem. Ideally, you would have caught this at design time. As you point out, you can't catch it at compile time (unless to switch to a "design by contract" language like Eiffel), so you catch it at run time.
And then ... it depends ...
If it's a desktop app then maybe a huge dialog box and exit is the quickest way to get it fixed, if it causes someone to report the error. If you can, it might also be an idea to send an email to the developer (e.g., if it's an in-house app).
If it's a mission-critical or life-critical, you might just have to restart the app (this is the general approach in embedded systems).
Whatever you decide, try to collect as much information as possible about the problem. For instance, you can roll your won macro to wrap around ASSERT which adds FILE and LINE).
I use the following:
#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
Upvotes: 0
Reputation: 37895
Apparently (I recently searched the web for "C static assert"), C++0x has a static_assert, and the C people are talking about something like that as well for the next C standard. Of course, this implies that there currently is no standard "static assert" in C.
Some people propose C preprocessor macros which define enums or structs which use a boolean expression and the ?:
operator to generate an illegal enum/struct definition if the conditional expression fails. (Above web search listed a number of such macro definitions.)
Personally, as I am always using gcc anyway, I just declare such functions as
foo_t function(moo_t *moo) __attribute__(( nonnull(1) ));
and and thus have the compiler give me a warning (-Wnonnull
, included in -Wall
) if I accidentally call the function with the parameter set to NULL
.
Upvotes: 0
Reputation: 6283
You can't get a compiler error if test is NULL, it is a runtime value, and it could depend on even user input, the compiler has no way to know its value.
To avoid the function being called with a NULL value, use assert:
assert(test != NULL);
This means: my code is not able to handle NULL as input. And it will abort at runtime.
Your function is supposed to return arbitrary_t and it is not returning anything.
You can also send the error back to the caller, in the return value that you are not using right now, for example returning an arbitrary_t* instead, which would be NULL if it could not be allocated (which will be the case if test_t was NUL). The caller would need to test for that.
Upvotes: 0
Reputation: 24375
It really depends on your use-case. If you have an interactive app, prompt and have the user correct the input. If it is a server process you might want to log. If the error is going to make your program go south then do the assert.
Upvotes: 0
Reputation: 31878
We really can't categorically answer this question. It depends highly on what the software is going to be used for. If it's providing radiation, you would want it to print the error and exit(1);
. If you're writing a business app, you probably want to log an error and just return. It's all about the context.
Upvotes: 4
Reputation: 181460
I would use an assert at the beginning of the function:
arbitrary_t test_dosomething(test_t* test) {
assert(test != NULL);
printf("%d", test->a); //do something w/ test
}
You won't get a compiler error. But when in development (debugging) your program will halt and point you to that particular assert
in the code.
Upvotes: 0
Reputation: 355347
If you never want the function to be called with a null pointer (i.e., the pointer not being null is a precondition to calling the function), you can use an assertion at the top of the function:
assert(test != NULL);
This can help you when debugging to find places in your code where you are calling the function with a null pointer.
Upvotes: 7