Would this be a valid use of NULL in C or are there other ways to solve this problem that are preferred?
// Send data
// cb_push returns NULL if it is successful
char uart_send(char c) {
void* ret = cb_push(w_buffer, &c);
if (ret != NULL) return c;
SETBIT(UCSR0B, UDRIE0);
return NULL;
}
In Java I would do like this, sort of, but in C I don't know what is good practice.
It's not really defined and there are different approaches depending on the library and/or function you're using. In general, there's no way to differentiate between 0 and NULL (in fact, NULL is usually just a preprocessor macro expanding to 0).
In general, the following possibilities are used, sometimes even matched within one library depending on the usage:
If a pointer is returnd, a return value of 0 usually indicates some kind of error.
Functions with status codes (or main entry points) usually return 0 in case there hasn't been any error.
There are functions returning 0 if something hasn't been successfull (i.e. they return a boolean value).
Some stdlib string functions return an "absurd" value in case there has been an error (or nothing found). For example, std::string::find() will return -1 if the sub string couldn't be found. This is however wrapped/hidden behind a constant named value (std::string::npos) to avoid throwing around "magic values".
Is there a perfect way? I don't think so, but it really depends on the specific use case. If you return a pointer, returning 0 in case of a mistake is just perfect. If you're returning status codes, I'd go with either macros (similar to windows API) or enums. Don't even worry about any specific values - only use the names.
Generally speaking, the C convention is to return 0 on success or a negative number if not.
Also, assuming your function is supposed to return some pointer and it failed to do so, the convention is to return NULL.
NULL is internally defined as #define NULL (void*)0 means a pointer pointing to zeroth location of memory.
Related
This question already has answers here:
Error handling in C code
(23 answers)
Closed 4 years ago.
I've inherited a C system which makes use of function return values to check for errors and exceptions; something like this:
#define OK 1
int create_cheese(const char * myType, float myCost, char * myCheese) {
// Do Stuff...
if // everything looks good
return 1;
else
return // error/exception code
}
int main() {
rc = create_cheese("cheddar", 12.99, &cheese);
if (rc != OK) { exit(rc); }
return 1;
}
Is this considered proper C technique?
These functions are not very, well, functional. In other words, they don't use the function return values as meaningful data relevant to program execution; they're used for error and exception handling. Thank you, Keith :^)
Is this considered proper C technique?
I have found no matching return 1 on success parallel in the C language or standard library.
C has at least 6 different ways it communicates errors. Many listed below.
OP's posted technique is a variation returning error/success status.
It suffers from 2 weaknesses
OK is too common an identifier and will likely collided with other code. Far too easy to find OK defined as 0.
Opposite zero-ness. OK as 0 is more common.
OP's error approach is not proper as it is yet another unnecessary variation on existing techniques.
Various C error / exception / the unhappy path handling
Return error/success (not data, but maybe error data)
Success is 0, else return a non-zero errno_t: Many ..._s() functions. (Similar to OP's - yet non-zero success)
Success is 0, else non-zero. remove(), raise()
Return data - a few (maybe only one) values indicate error/special.
NULL is bad, else a pointer. fgets(), setlocale(), bsearch()
NULL is maybe bad, else a pointer. malloc
0 is bad, else various others are good. fread()
-1 is bad, else various others are good. time(), fseek()
EOF - a negative. 0 or more is good. fgetc()
FP_ILOGB0, FP_ILOGBNAN else some int. ilogb()
any negative is bad, else value is informative. printf().
Largest few values have special meaning, else some unsigned. mbrtoc16()
Via state/instance object: Many I/O functions return EOF to indicate end of file or I/O error. Other functions used to determine detail. feof(), ferror().
Global
Error code errno: strtol()
Floating-point environment: fegetexceptflag()
Not-a-number: NaN sits in limbo between error codes and values. log(negative_x), atanh(x_more_than_1)
UB: Simply not handling the error in a specified way: e.g. 1/0
One style I do not see with the standard C library, though is other libraries, is bool foo(..., int *error_code) - passing is a place to store/update the error detail.
Since C doesn't support exceptions, the only way to test for an error after a function call is to examine a designated error holding variable. There are a few ways you can do this:
Return the error / success indication from the function (i.e. errno_t foo(int bar);)
Make the error / success indication an output pointer parameter (i.e. void foo(int bar, errno_t *error_code);)
Use an operating system error indicator (i.e. SetLastError on Windows, or errno).
I'm a fan of method #2, since it's a lot harder to ignore that there's an error parameter with:
errno_t err;
myfunction(100, &err);
Instead of:
errno_t err = myfunction(100); // You could just as easily not assign the return value
This is the correct way, but you can follow the rules of the existing macro-constant EXIT_SUCCESS (= 0) and EXIT_FAILURE (= -1). So I suggest to return a value != 0 when there is an error .
Yes, this is perfectly valid way of handling errors, particularly as C doesn't have exceptions like C++ or Java does.
You check the return value to see if the function was successful or not, and use the parameters to get back information from the function. Plenty of library functions work in this manner, so it's a well known idoim in C.
You can also mix returning meaningful values and error codes. For example, the write library function returns the number of bytes read, or -1 if an error occurred. In the case of an error, it also sets the global errno which contains the actual error code.
The convention in C (it's almost formalised in the standard) is to return 0 for success. So your returning 1 is idiosyncratic and ought to be changed.
This can be extended to return negative for failures and positive for near-failures.
When returning from main you ought to assume that the operating system will only deal with 8 bits of the return value, and possibly unsigned too which, maddeningly, is in contradiction with returning a negative for failure! That's the good thing about standards: there are so many to choose from.
I often see code that checks for errors from POSIX functions by testing for less than zero instead of explicitly defined and the usually only error code used -1. That is
ret = function();
if (ret < 0) {
...
}
vs
ret = function();
if (ret == -1) {
...
}
Is there any purpose for the first practice? Is comparing with 0 faster than comparing with -1 on some architectures? Does C or POSIX standard make any guarantees that the first alternative won't break in the future if the only error code defined now is -1? If not, should it be considered bad practice or not? (I guess it's unlikely for most of the functions to change in such manner that would cause lot of already written code to broke?).
EDIT: To make the question more clear: I am talking only about functions that exclusively return -1 as an error code as defined by standard. I know there are some that don't. I saw the < 0 check on these functions in many places instead of == -1. Hence the question.
Firstly, some functions have only one error code, some have more. For one example, pthread_create is a POSIX function that can return more than one error code. When I don't care about specific error codes, I also don't want to care about how many there are of them. In such cases checking for negative return is just a reliable universal no-maintenance approach that covers all cases. Additionally, errors in POSIX specification are typically described in terms of manifest constants, not in terms of specific numerical values.
Secondly, I'm not sure what exactly POSIX says about the extensibility of error returns for existing functions, but naturally I would prefer to anticipate such possibility in my code.
Thirdly, in general, checking for "negative" value on many (if not most or all) processors is more efficient that checking for a specific value. Many CPU's have a dedicated CPU status flag that designates negative result. That means that testing for negative values does not have to involve a literal operand. For example, on x86 platform test for negativity does not have to involve a comparison with literal 0. Comparisons with specific values will generally require embedding that specific value into the machine instruction, resulting in a slower instruction. However, in any case "special" values, like 0, -1, 1 etc., can be tested for using more clever and efficient techniques. So I doubt that comparisons in question are done that way for performance reasons.
It's mostly historical accident. There used to be (pre-POSIX) UNIX-like systems that returned -errno on error instead of -1, so you didn't have to use a global errno variable. So checking for < 0 would work on such systems.
You can see this history still in Linux -- system calls return -errno and the C library checks for values in the range [-4096..-1]. If the return value is in that range, the library negates it and stores it in errno (which the kernel knows nothing about) and then returns -1.
If a function is defined to return -1 on error and 0 on success, then use -1 to test for error and 0 to test for success.
Doing anything else is inaccurate and increases the probability of malfunction.
If one wants to really be on the save side one should try to detect all the cases where a function returns a value not being defined as return value and do an addtional assert on this case. For my introducing example this would be all values >0 and <-1.
That's it.
int func(void); /* Returns 0 on success and -1 on error. */
int main(void)
{
int result = func();
switch result
{
case 0:
/* Success. */
break;
case -1:
/* Failure. */
break;
default:
/* Unexpected result! */
break;
}
return 0;
}
What I saw in an if statement was like this.
if((var = someFunc()) == 0){
...
}
Will the statement
(var = someFunc())
always return the final value of var no matter what environment we are in?
That is just a one-line way of assigning to a variable and comparing the returned value at the same time.
You need the parentheses around the assignment because the comparison operators have higher precedence than the assignment operator, otherwise var would be assigned the value of someFunc() == 0.
This is simply wrong. var is assigned, and then its value is overwritten by a constant 0. The return value of the function is therefore lost, and the if always fails. Most compilers would probably issue a warning about that nowadays, both because of the assignment within an if and because of the impossible if that results. The right way to do what was probably intended is
if((var = someFunc()) == 0) {
(Mind you, this might also be malicious code trying to introduce a vulnerability under the guise of a common newbie mistake. There was a case recently where someone tried to smuggle a check into the Linux kernel where they assigned the UID to 0 (i.e., root) while pretending to check for being root. Didn't work, though.)
This is correct, I use it all the time
if ((f=fopen(s,"r"))==NULL)
return(fprintf(stderr,"fopen(%s,r) failed, errno=%d, %s\n",s,errno,strerror(errno)));
/* successfully opened file s, read from FILE *f as you like */
I also use it when I calloc() memory.
You're assigning the return value of someFunc (fopen or calloc in my cases) to a variable AND also testing that return value, it's a semantic shortcut assuming you'll never want to debug the assignment and the test separately.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Error handling in C code
Let's say you have a function:
int MightWork(){
// if it works
return x;
// if it fails
return y;
}
what should x and y be?
because I have another function:
if (MightWork){
// do stuff #1
}else{
// do stuff #2
}
I know for this particular example, using a return value of 1 will take the second code block to "do stuff # 1" and using a return value of 0 will take the second code block to "do stuff #2"
My question is what is preferred style in C to do this? Does a return value of 0 for a function indicate success and any other value indicates failure? Or vice versa? Or values under 0?
I'd like to make sure I'm writing my C code with the current style. Thanks!
For non-pointer success/fail:
0 => success
-1 => fail
For pointer functions:
NULL => fail
everything else => success
Both are used, and it generally depends on if multiple error codes can be returned.
If your function will only "succeed" or "fail" with no additional information, I would recommend you return 0 for failure and 1 for success, because it's simpler and more semantically valid.
If your function may fail with multiple status codes, the only way to go is have 0 for success and other values for failure representing different statuses.
In a conditional context, integers evaluate to "true" if they're non-zero and "false" if zero, so you should return 0 on failure if you want to use the function in that way, and make sure not to return 0 in the successful branch.
There's no one right answer.
If your function is named/documented as evaluation of a predicate of some sort, then it should return a nonzero value (1 if convenient) for "true" and 0 for false.
If your function returns a pointer, 0 (null pointer) is just about the only reasonable way to report failure. Conventions like returning (void *)-1, MAP_FAILED, SEM_FAILED, and such are hideous and should not be copied. If you need to report a reason for failure, add an extra int *errorcode argument and include if (errorcode) *errorcode = reason; at the end of your function to allow callers that don't care about the reason to pass a null pointer.
If your function returns a numeric value such that only certain range values make sense (for instance only non-negative integers, or only finite floating point values) then use out-of-range values for error codes (e.g. negative integers or NaN/infinity) as error codes. If you don't have enough possible codes (for example only NaN) then use the int *errorcode approach described above.
Historically, a return value of 0 usually indicates success, while a return value of -1 indicates failure. You can also use more output values to give the user of the function more detailed information about the return state. It's another tradition to set a global error code variable, see e.g. GetLastError and SetLastError on Windows.
1 = true
0 = false
in general....
sometimes people use -1 for "error"
another way to handle this is with enums and sometimes #defines. Though many times people don't use this unless there is many errors.... and usually multiple errors are handled by various negative numbers.
In my opinion both could work , but in different case.
If you make the function to do some operation , return 0 for success , -1 for failed,
and set errno to appropriate value so that the caller could check it to know the detail of failure.
Sometimes people also use different return values to mean different failures.
If you would like the function to test some condition , you should make it return either
TRUE or FALSE, and use if (XXX() == TRUE) later . The form of if (XXX()) is not recommended, though many people do that to save times of typing keyboard .
TRUE and FALSE is not a built in data type in C , however many programming environments will define it as TRUE = 1 and FALSE = 0, you can do it yourself if you are not working in such an environment.
use #define.
#define TRUE 1
#define FALSE 0
this helps any other person to understand your choice of standard for true and false value.
Also, if the program code gets bigger, keeping track of the constants become difficult and might confuse. Using #define for constants is always a good practice.
I want the function getCategory() to return "invalid" , instead of printing the word "invalid" (i.e instead of using printf ) when input to the function is invalid (i.e.when either height or weight are lower then zero).
please help:
#include<stdio.h>
#include<conio.h>
char getCategory(float height,float weight)
{
char invalid = '\0';
float bmirange;
if(height<=0 || weight<=0)
return invalid;
else
{
height=height*0.01; //1 centimeter = 0.01 meters
bmirange=[weight/(height*height)];
if(bmirange< 15 )
return starvation;
}
}
int main()
{
char Category;
float height,weight;
printf("enter height");
scanf("%f",&height);
printf("enter weight");
scanf("%f",&weight);
Category=getCategory(height,weight);
if(Category == 0)
printf("invalid");
else
printf("%c", Category);
}
NOTE: the original question has been altered many, many times and the code has changed just as often, introducing new errors in each iteration. I leave this answer as it answered the original code, see history. Below this answer there's an update giving advice instead of code, as that seems more appropriate here.
Hmm, astander removed his answer. But perhaps this is what you should actually have:*
char getCategory(float height,float weight)
{
char invalid = '\0';
if(height<=0 || weight<=0)
return invalid;
return 'c'; /* do something for the valid cases */
}
* originally the question contained height || weight <= 0 and no value for variable invalid.
Notes on the code:
With proper indentation, your program flow becomes clearer. I corrected your if-statement, assuming this was your intend, actually. The last line should contain what you currently left out in your question. I added an initialization in the first line, because having a value is better then not having a value (which means: if you don't initialize, it can be anything, really).
In your calling code, you can do this:
Category = getCategory(height, weight);
if(Category == 0)
printf("invalid");
else
printf("%c", Category);
which actually prints the word "invalid" to the output, if that was your intend.
Update: based on new text in the question, it's clear that the asker wants something else, so here's a new answer. I leave the above, it's still valid with the original question.
You're now asking not to print the word "invalid" and not to use a special value for the invalid case. Instead, you ask to return "invalid", which I understand as returning the string with the value "invalid" (which, taken in itself, is still returning a special value).
You cannot do it
In short: you cannot do that. The current function has return type char. I don't know the purpose of your function, but I'm sure you've given it some thought and there's a reason for using a char. A char can only contain one character. And the word "invalid" is multiple characters. You have a few options, choose whichever suits you best:
Other ways
change the return type to be string instead of char, this requires redesign of all code involved;
settle with returning a special value. You don't show the body of your function, but if it would normally never return \0, you can use that value, as in my example above. Of course, you can choose any other char value;
raise an exception and use a try/catch in the body. But you use C, not C++. Here's a link that describes using C++-style exception handling for C, but this may be a bit out-of-bounds, learning C can better be taken on a small step at the time.
What's commonly best practice
In normal situations, it is common to choose either special-case values (typical in older or more basic languages like C or assembler) or exceptions (typical for more structured languages like C++, Java, Python). It's commonly considered bad practice to change a complete function for the purpose of special-cases (like invalid input).
Why
Instead, the caller of the function should deal with these special cases. The reason for this is a very important rule in programming: the function can never know beforehand what users of that function want to do when something bad happens (illegal input). One may choose to print "Illegal input" (for commandline users), another wants to quit the program (for in a library) and yet another wants to ignore and do nothing (for automatic processing). In short: what you are trying to achieve, you should try to achieve differently (see option 2 and 3 above, and my original solution).
Teachers and textbooks
Using this approach is by far the easiest and also best to understand for any (future) co-workers as it follows common computer practices. Of course, I haven't seen your assignment or textbook, so I can't tell in what direction they want a solution, and it won't be the first textbook or teacher to first show you the wrong path, let you tremble, and then show you the right path.
The getCategory method doesn't always return (because of the if statement). Also, not sure about the height in if statement. Add another return invalid at the end of the method.
char getCategory(float height,float weight)
{
char invalid;
if(height<=0 || weight<=0)
return invalid;
return 0
}
you need to (very carefully) pore over your textbook to ascertain the multitude of errors in the above code.
1, your test in getCategory will almost certainly not do what you want it to do.
2, you ARE returning invalid in some cases (but not all, see #1). However, there is no way to know that as invalid has no known value.
3. in other cases, getCategory returns no value at all
You're defining a variable named invalid. Its contents are undefined (it could be anything from -128 to 127). When you return this variable you're returning anything; do you want to assign something to the invalid variable before you return it? e.g.
char invalid;
invalid = 'i';
if ( ... ) {
return invalid;
} else {
return 0;
}
What does invalid should be mapped to? You should have a convention like this:
char invalid_category = '?';
or perhaps:
#define INVALID_CATEGORY '?'
This is better defined outside of the getCategory function so that the calling code can access it.
Also it isn't evident what your code returns when valid arguments are passed to it.
By the way, in your function getCategory, you have a variable that is not used nor declared - starvation. Where does that come from? I doubt that is a global variable.
Also, the variable bmirange does not make sense nor would it compile
bmirange=[weight/(height*height)];
as you can see that is a left hand side expression (LHS) but you have used an array subscript operators on the right hand side of expression (RHS). That is an illegal statement!
What was your intention there? Was that meant to be a pair of parenthesis?
Can you confirm this?
A lot of the answers are confusing because the OP did not make themselves clear on what is the error nor an explanation as to what is going on which is leading others to end up with code posted that does not satisfy the OP.
Hope this helps,
Best regards,
Tom.