Simplify and reduce the amount of code without using macros [closed] - c

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
Sometimes, there are situations where the repetition of simple code blocks is unavoidable. To illustrate, with this example code:
Note: this code is for illustration purpose only, real-life code is much bigger and more complex. Also it may contain errors, but the point of this question is not that.
switch(cmd) {
case CMD_BLOCK_READ:
if(current_user != key) {
ERROR("Access violation - invalid key!");
res = CR_ACCESS_DENIED;
break;
}
if(current_state < STATE_BUSY) {
WARN("Command %s is not allowed in this state!", cmd_name[cmd]);
res = CR_NOT_PERMITTED;
break;
}
if(ioctl(fd, HPI_CTL_BR) != 0) {
WARN("Handshake failed (%s). Aborted!", strerror(errno));
res = CR_TIME_OUT;
goto post_resp;
}
if(block_read(id) != 0) {
ERROR("Failed to read %d block (%s)! Aborted!", id, strerror(errno));
res = CR_FAIL;
goto send_nop;
}
res = CR_SUCCESS;
break;
case CMD_BLOCK_WRITE:
if(current_user != key) {
ERROR("Access violation - invalid key!");
res = CR_ACCESS_DENIED;
break;
}
if(current_state < STATE_BUSY) {
WARN("Command %s is not allowed in this state!", cmd_name[cmd]);
res = CR_NOT_PERMITTED;
break;
}
if(ioctl(fd, HPI_CTL_BR) != 0) {
WARN("Handshake failed (%s). Aborted!", strerror(errno));
res = CR_TIME_OUT;
goto post_resp;
}
if(block_write(id) != 0) {
ERROR("Failed to write %d block - %s. Command aborted!", id, strerror(errno));
res = CR_FAIL;
goto send_nop;
}
res = CR_SUCCESS;
break;
case CMD_REQ_START:
if(current_state < STATE_READY) {
WARN("Command %s is not allowed in this state!", cmd_name[cmd]);
res = CR_NOT_PERMITTED;
break;
}
state = STATE_BUSY;
if(ioctl(fd, HPI_CTL_BR) != 0) {
WARN("Handshake failed (%s). Aborted!", strerror(errno));
res = CR_TIME_OUT;
goto send_nop;
}
if(block_read(id) != 0) {
ERROR("Failed to read %d block (%s)! Aborted!", id, strerror(errno));
res = CR_FAIL;
goto post_resp;
}
res = CR_SUCCESS;
break;
}
/* The remaining 28 or so similar commands */
}
As you can see, due to minor differences and the extensive use of break/goto statements, it is not possible to use functions or inlines. What I usually do is define some macros:
/* NOTE: DO NOT USE these macros outside of Big Switch */
#define CHECK_KEY(_key) \
if(current_user != (_key)) \
{ \
ERROR("Access violation!"); \
res = CR_ACCESS_DENIED; \
break; \
}
#define CHECK_STATE(_state) \
if(current_state < _state) \
{ \
WARN("Command %s is not allowed in this state!", cmd_name[cmd]); \
res = CR_NOT_PERMITTED; \
break; \
}
#define HANDSHAKE(_fail) \
if(ioctl(fd, CTL_BR) != 0) \
{ \
WARN("Handshake failed (%s). Aborted!", strerror(errno)); \
res = CR_TIME_OUT; \
goto _fail; \
}
#define BLOCK_READ(_id, _fail) \
if(block_read((int)(_id))!= 0) \
{ \
ERROR("Failed to read %d block (%s)! Aborted!", (int)_id, strerror(errno)); \
res = CR_FAIL; \
goto _fail; \
}
#define BLOCK_WRITE(_id, _fail) \
if(block_write((int)(_id)) != 0) \
{ \
ERROR("Failed to write %d block - %s. Aborted!", (int)_id, strerror(errno)); \
res = CR_FAIL; \
goto _fail; \
}
..and write the same code using them. The code becomes much smaller and (arguably) more readable:
switch(cmd)
{
case CMD_BLOCK_READ:
CHECK_KEY(key);
CHECK_STATE(STATE_BUSY);
HANDSHAKE(post_resp);
BLOCK_READ(id, send_nop);
res = CR_SUCCESS;
break;
case CMD_BLOCK_WRITE:
CHECK_KEY(key);
CHECK_STATE(STATE_BUSY);
HANDSHAKE(post_resp);
BLOCK_WRITE(id, send_nop);
res = CR_SUCCESS;
break;
case CMD_REQ_START:
{
CHECK_STATE(STATE_READY);
state = STATE_BUSY;
HANDSHAKE(send_nop);
BLOCK_READ(id, post_resp);
res = CR_SUCCESS;
break;
}
/* The remaining 28 or so similar commands */
<..>
The code looks more like some kind of scripting language than good old C and is really ugly, but I'm willing to sacrifice that for the sake of readability.
The question is how do you cope with similar situations? What are more elegant solutions and best practises?
P.S. I admit that in general case macros and goto statement is a sign of bad design, so no need to flame about how evil they are or how poor my programming style is.

I'm not going to claim that the Python source code is the paragon of organization, but it contains (IMHO) a good example of macros being used to simplify a complex piece of code.
The Python main loop implements a bytecode-executing stack-based VM. It contains a huge switch-case with one case for every opcode Python supports. The dispatch for an opcode looks like this:
case STORE_ATTR:
w = GETITEM(names, oparg);
v = TOP();
u = SECOND();
STACKADJ(-2);
err = PyObject_SetAttr(v, w, u); /* v.w = u */
Py_DECREF(v);
Py_DECREF(u);
if (err == 0) continue;
break;
where TOP, SECOND and STACKADJ are all defined as macros operating on the stack object . Some macros have alternate #defines used to assist with debugging. All of the opcodes are written in this way, and it helps make the implementation of each opcode much clearer by expressing the logic in this sort of miniature scripting language.
In my view, careful, judicious and limited use of macros can improve code readability and make the logic clearer. In your case, where the macros hide some small but nontrivial functionality, it can be useful to have macros to standardize the implementation and ensure that you don't have multiple copies of the same snippets of code to update.

In such situations I usually consider whether the cases may be reasonably described with a data, which are then processed in a single common block of code. Sure it cannot be done always, but often it is possible.
In your case it might lead to something similar to the following:
#define IO_NOOP 0
#define IO_READ 1
#define IO_WRITE 2
struct cmd_desc {
int check_key; /* non-zero to do a check */
int check_state;
int new_state;
void* handshake_fail;
int io_dir;
void* io_fail;
};
const struct cmd_desc cmd_desc_list[] = {
{ 1, STATE_BUSY, -1, &&post_resp, IO_READ, &&send_nop }, /* CMD_BLOCK_READ */
{ 1, STATE_BUSY, -1, &&post_resp, IO_WRITE, &&send_nop }, /* CMD_BLOCK_WRITE */
{ 0, STATE_READY, STATE_BUSY, &&send_nop, IO_READ, &&post_rep } /* CMD_REQ_START */
};
const struct cmd_desc* cmd_desc = cmds[cmd];
if(cmd_desc->check_key) {
if(current_user != key) {
ERROR("Access violation - invalid key!");
return CR_ACCESS_DENIED;
}
}
if(cmd_desc->check_state != -1) {
if(current_state check_state) {
WARN("Command %s is not allowed in this state!", cmd_name[cmd]);
return CR_NOT_PERMITTED;
}
}
if(cmd_desc->new_state != -1)
state = cmd_desc->new_state;
switch(cmd_desc->io_dir) {
case IO_READ:
if(block_read(id) != 0) {
ERROR("Failed to read %d block (%s)! Aborted!", id, strerror(errno));
res = CR_FAIL;
goto *cmd_desc->io_fail;
}
break;
case IO_WRITE:
if(block_write(id) != 0) {
ERROR("Failed to write %d block (%s)! Aborted!", id, strerror(errno));
res = CR_FAIL;
goto *cmd_desc->io_fail;
}
break;
case IO_NOOP:
break;
}
res = CR_SUCCESS;
Notes I used "Labels as Values" extension of gcc for the goto labels (http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html). In standard C you might use function pointers instead but that would require some reorganization of the code and I do not have enough info for that.

With the code you posted, there is no reason you couldn't have used functions. This would be the "Extract Function" refactoring pattern. To handle the gotos, just leave them in your main function, and call them or not based on the function result.
http://www.refactoring.com/catalog/extractMethod.html
Also, you've really made a mess of things by using variables in the macros that are not passed in. This means you can't reuse them easily and they are arguably worse than writing the whole thing long-hand. If you passed in everything that is used by the macro, then it is more useful. Then you get a duck-typing style coding, which can be used effectively.
Also, you are using C, so you shouldn't "avoid" macros. They are incredibly useful, primarily for code generation. (i.e. stringification and concatentation) Many C++ and some other say "macros are evil". This is C, macros are not evil.

Related

How to return an error from a returning value function in C language [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I am wondering for a while what is the best practice to handle errors in returning values function in C.
First, I would like to introduce the need then share a few solutions that I tried and to hear different ideas.
The issue is when I have a returning value function, this function can return any value in the range, and the function sometimes has a problem that it must return as well to the calling function, it cannot use the traditional return for that cause.
How can I handle that error in the calling function?
few notes:
1. I am an Embedded programer, and I am keen on keeping my function reentrant (pure) functions in a way that different interrupts won't harm the globals, I hardly use globals in my code.
I can't handle it with 0 or -1 because it is a valid return as well.
the errno solution doesn't support pure functions as well as 1.
4.I tried using structs of return which I have one field for the value and one field for the error if it has occurred.
unsigned int squre(unsigned int num)
{
return num*num;
}
programmer say I would like to have handle for overflow.
struct returnUnsignedint squre(unsigned int num)
{
struct returnUnsignedint returnValue;
if (num>65535) { //my embedded system over flow
returnValue.error = 1;
}
returnValue.value = num*num;
return returnValue;
}
is there a better option out there?
Let me know if you have different point of view, or solutions.
I would appreciate any help, thanks!
There's no "one size fits all" solution, since it depends on needs of your program.
However, there are a few possibilities.
One way is to specify that one possible return value of your function can indicate an error occurred. For example, since not every value of an unsigned is the square of another, pick a suitable value and return that.
unsigned sqre(unsigned x)
{
if (x == 0U)
{
return 0U;
}
else if (UINT_MAX/x >= x) /* use fact that UINT_MAX is typically not a perfect square */
{
return x*x;
}
else
{
return UINT_MAX;
}
}
(Note, in the above, that I have eliminated your implicit assumption that unsigned is at least 32-bit, by avoiding use of the magic value 65535).
Another option is to do what some standard library functions do: return 0 (or, in the case of unsigned, return 0U, on error) even if it is feasible that value is valid. That means your function always returns a usable value, but the caller will need to decide what to do if your function returns zero.
Another option is to return a data structure
struct Return
{
unsigned value;
int error;
};
struct Return sqre(unsigned x)
{
struct Return retval;
retval.error = 0;
if (x == 0)
{
retval.value = 0U;
}
else if (UINT_MAX/x >= x) /* use fact that UINT_MAX is typically not a perfect square */
{
retval.value = x*x;
}
else
{
retval.error = 1;
}
return retval;
}
The trade-off is that forces the caller to create an instance of the struct and then check or extract data from it.
Another is to provide a second argument that provides an error indication.
unsigned sqre(unsigned x, int *error)
{
*error = 0;
if (x == 0U)
{
return 0U;
}
else if (UINT_MAX/x >= x) /* use fact that UINT_MAX is typically not a perfect square */
{
return x*x;
}
else
{
*error = 1;
return 0U; /* falling off end without a return statement gives undefined behaviour */
}
}
The disadvantage of the above is that the caller can forget to check the error condition. It is trivial to modify the above so it checks if error is NULL and then doesn't modify *error (and then allow the caller to specify a NULL to indicate no interest in the error condition).
An alternative is for the function to return the error condition, and require the caller to pass the address of a variable to hold the result (if no error occurs). A disadvantage of this is that the result from the function can't be used directly in larger expressions.
Since, technically, overflow of unsigned gives well-defined behaviour (essentially modulo arithmetic), use your version that does no checks. This option isn't feasible if the function returns a signed int (since overflow gives undefined behaviour). This requires the caller to deal with the fact that the returned value may be truncated (e.g. high order part of the value lost).
Yet another option is for the function to terminate with prejudice if an overflow would occur. For example;
unsigned sqre(unsigned x)
{
assert(x == 0 || UINT_MAX/x < x); /* from <assert.h> */
return x*x;
}
This removes the responsibility of the caller to check. However, the caller (if program termination is undesirable) must then ensure the argument passed is valid. Alternatively, the end-user would need to be willing to accept that the program may terminate on bad data.
Another option is to return the error code and write the output value to a parameter:
int sqr( unsigned int num, unsigned int *result )
{
if ( num > 65535 )
return 0;
*result = num * num;
return 1;
}
This isn’t always the most convenient option (especially if you want to use sqr as part of a larger arithmetic expression), but it should meet your requirements.
EDIT
Of course, you could always go the other way - return the value and write the error code to a parameter:
unsigned int sqr( unsigned int num, int *err ) { ... }
but frankly I prefer the first version, since you aren't tempted to use the return value unless you know the operation succeeded.
Following up John's answer I propose an additional macro to be able to use the function in a "larger arithmetic expressions"
#include <stdlib.h> /* for EXIT_xxx macros */
#include <stdio.h> /* for perror() */
#include <errno.h> /* for errno */
int sqr(unsigned int num, unsigned int *psqr)
{
int result = 0;
if (NULL == psqr)
{
result = -1;
errno = EINVAL;
}
else if (num > 0xffffU)
{
result = -1;
errno = ERANGE;
}
else
{
*psqr = num * num;
}
return result;
}
#define SQR(x, y) \
((-1 == sqr(x, &y)) \
? (perror("sqr() failed"), exit(EXIT_FAILURE), 0U) \
: y \
)
Some tests below (please note that the macro SQR() has to end the program if sqr() fails):
int main(void)
{
unsigned int r, i;
puts("Test case 1:");
i = 42;
if (-1 == sqr(i, &r))
{
perror("sqr() failed");
}
else
{
printf("sqr(%u) = %u\n", i, r);
}
puts("Test case 2:");
i = 0x10000;
if (-1 == sqr(i, &r))
{
perror("sqr() failed");
}
else
{
printf("sqr(%u) = %u\n", i, r);
}
puts("Test case 3:");
if (-1 == sqr(i, NULL))
{
perror("sqr() failed");
}
else
{
printf("sqr(%u) = %u\n", i, r);
}
puts("Test case 4:");
r = SQR(1, r) + SQR(2, r);
printf("sqr(%u) + sqr(%u) = %u\n", 1, 2, r);
puts("Test case 5:");
r = SQR(0x10000, r) + SQR(2, r);
printf("sqr(%u) + sqr(%u) = %u\n", 0x10000, 2, r);
puts("Test case 6:");
r = SQR(NULL, r) + SQR(2, r);
printf("sqr(%u) + sqr(%u) = %u\n", 0x10000, 2, r);
return EXIT_SUCCESS;
}
The output is:
Test case 1:
sqr(42) = 1764
Test case 2:
sqr() failed: Numerical result out of range
Test case 3:
sqr() failed: Invalid argument
Test case 4:
sqr(1) + sqr(2) = 5
Test case 5:
sqr() failed: Numerical result out of range
Test case 6 is never reached as test case 5 ends the program.

Bogus 'may be used uninitialized

I am getting an unitialized warning in the following code, and I am stumped trying to figure out why.
I can't see a code path where it is used uninitialized.Can anyone please help?
Also, I could use some adivce on if my gotos are not used well or if there is a cleaner way of doing this.
In function ‘handle_comp_enc’:
fs/compress.c:101:8: warning: ‘write_cdata’ may be used uninitialized in this function [-Wmaybe-uninitialized]
kfree(write_cdata);
Code:
#define ENC (1UL << 1)
#define ZIP (1UL << 2)
#define ENC_ZIP_ENABLED(cmp_enc_flags) ((cmp_enc_flags) & (ENC | ZIP)) == (ENC | ZIP)
int handle_comp_enc(unsigned long comp_enc_flags, unsigned char *read_data,
size_t read_len, unsigned char *write_data, size_t *write_len2) {
unsigned char *write_cdata, *rd_enc_data;
size_t write_clen, enc_src_len;
int err;
if (ENC_ZIP_ENABLED(comp_enc_flags)){
write_cdata = kmalloc(get_compress_fsize(PAGE_SIZE), GFP_KERNEL);
if (!write_cdata) {
err = -ENOMEM;
goto zip_only;
}
}
else if(!(comp_enc_flags & ENC))
write_cdata = write_data;
else{
rd_enc_data = read_data;
enc_src_len = read_len;
goto enc_only;
}
err = do_compress(read_data, read_len, write_cdata, &write_clen);
if (err < 0) {
goto out_enc_zip;
}
if (!(comp_enc_flags & ENC)) {
*write_len2 = write_clen;
goto zip_only;
}
rd_enc_data = write_cdata;
enc_src_len = write_clen;
enc_only:
err = do_skcipher_encrypt(rd_enc_data, enc_src_len, write_data, write_len2);
if (err < 0) {
}
out_enc_zip:
if (ENC_ZIP_ENABLED(comp_enc_flags))
kfree(write_cdata);
zip_only:
return err;
}
Compiler try it's best to produce warning, as the message say "maybe", the compiler don't know that ENC_ZIP_ENABLED(comp_enc_flags) will be false at the label out_enc_zip. Your code don't use an uninitialized value.
That say, I strongly disagree about your use case of goto, your code is unreadable, I take a lot of time just to understand where the code was going.
Your code could be simplified a lot, I'm not sure at 100% that this code have the same behavior as I said your code is hard to read:
#define ENC (1UL << 1)
#define ZIP (1UL << 2)
int handle_comp_enc(unsigned long comp_enc_flags, unsigned char *read_data,
size_t read_len, unsigned char *write_data, size_t *write_len2) {
if ((comp_enc_flags & (ENC | ZIP)) == (ENC | ZIP)) {
unsigned char *tmp = kmalloc(get_compress_fsize(PAGE_SIZE), GFP_KERNEL);
if (!tmp) {
return -ENOMEM;
}
size_t size;
int err = do_compress(read_data, read_len, tmp, &size);
if (!(err < 0)) {
err = do_skcipher_encrypt(tmp, size, write_data, write_len2);
}
kfree(tmp);
return err;
}
else if (!(comp_enc_flags & ENC)) {
return do_compress(read_data, read_len, write_data, write_len2);
}
else {
return do_skcipher_encrypt(read_data, read_len, write_data, write_len2);
}
}
Yeah it looks like a false positive. In your if-else if-else, you only initialize the variable inside the if and else if statements. Apparently you got the tool confused with goto or some such.
But that's not really important, as the origin of the problems is the function design. You don't default initialize variables and you have a tight coupling between memory allocation and the actual algorithm. The use of goto here is ok but it reduces readability somewhat.
I would split this in two functions, where you leave memory handling and error handling to an outer function. Something along the lines of this pseudo code would be much more readable:
int wrapper_function ( ... )
{
unsigned char *write_cdata = NULL;
int err = initialize_me_to_something.
if(ENC_ZIP_ENABLED(comp_enc_flags))
{
write_cdata = kmalloc (...
if(write_cdata == NULL)
{
return -ENOMEM;
}
}
else
{
if(!(comp_enc_flags & ENC)
{
write_cdata = write_data;
...
}
else
{ // some special case
err = do_skcipher_encrypt(...
return err;
}
}
err = do_the_actual_job(write_cdata, otherparameters);
if (err < 0)
{
cleanup();
}
return err;
}
goto is not necessarily evil, but neither are multiple return statements. They are both frowned upon with more or less rational arguments provided. However, multiple return statements tend to improve readability quite a bit over the "on error goto" pattern. Most importantly, they tend to naturally give a better program design with multiple small functions instead of a single big one.
As a side effect, you get rid of some extra branching instructions, which might give a slight performance improvement.

Return error code after first detected error

I have a function which does some initialization and calls other functions, each of which returns an error code. I want to be able to return from this function after the first detected error like this:
int error_code = FirstFunction();
if (error_code != 0) {
return error_code;
}
error_code = SecondFunction();
if (error_code != 0) {
return error_code;
}
// etc...
However, not only does this look rather cumbersome, it also has multiple return statements, and for compliance reasons at my company this is not allowed.
How can I rearrange this so that there is only one return statement, but still stop after the first error code? The only way I can think of is to do nested if statements:
int error_code = FirstFunction();
if (error_code == 0) {
error_code = SecondFunction();
if (error_code == 0) {
error_code = ThirdFunction();
// etc...
}
}
return error_code;
But this could get unreasonable pretty fast. Is there another way to do this?
EDIT: In my program, return code of 0 means success (OK) and non-zero means failure/error (NOT OK)
You don't have to nest all the function calls, the code below do the job as well and should comply with your code writing rules:
error_code = FirstFunction();
if (error_code == 0) {
error_code = SecondFunction();
}
if (error_code == 0) {
error_code = ThirdFunction();
}
// etc...
return error_code;
Here is another lean method that can return different error codes depending on which function fails:
int func(void)
{
int code;
int error_code = (code = FirstFunction()) ? code :
(code = SecondFunction()) ? code :
(code = ThirdFunction()) ? code : 0;
/* ... */
return error_code;
}
Lean and clean (like this one, but avoiding the disliked gotos):
int foo(void)
{
int error_code;
do {
if (0 != (error_code = FirstFunction()))
{
break;
}
if (0 != (error_code = SecondFunction()))
{
break;
}
...
} while (0);
return error_code;
}
This, BTW, follows the more common pattern: 0 is OK, everything else isn't. Adjust as needed)
You could even obfuscate this using a macro:
#define RUN_AND_BREAK_ON_ERROR(rc, f, ...) \
if (0 != (rc = f(__VA_ARGS__))) \
{ \
break; \
}
int foo(void)
{
int error_code;
do {
RUN_AND_BREAK_ON_ERROR(error_code, FirstFunction, <args go here>);
RUN_AND_BREAK_ON_ERROR(error_code, SecondFunction, <args go here>);
...
} while (0);
return error_code;
}
if( (error_code = FirstFunction()) || (error_code = SecondFunction()) || ... ){
return error_code ;
}
return error_code; //denoting no error.
This would return only the first function which returns nonzero. The idea is that for if statement the first function that returns nonzero would short-circuit the whole evaluation and returns the error_code from the function which returned non-zero error_code. Also another thing is value of an assignment statement is the value assigned. That's why this works.
A more easier way would be to sequential if-else
if( error_code = FirstFunction() ) {}
else if( error_code = SecondFunction() ) {}
...
return error_code;
If all these functions take the same type of parameters and have the same return type, you could put them in a function array and iterate over it. When an error is found, it simply breaks out of the loop and returns.
int (*function_array[max_array])();
/*Fill the array with the functions you need*/
for(i=0;i<max_array;i++){
if((error_code=function_array[i]())!=OK){
break;
}
}
return error_code;
(OK is whatever the success return value is for these functions)
Well, there's the one used e.g. in the Linux kernel:
int somefunc(whatever)
{
if (do_something()) {
ret = -EINVAL;
goto err;
}
if (do_something_else()) {
ret = -EPERM;
goto err;
}
/* ... */
ret = 0;
err:
some_mandatory_cleanup();
return ret;
}
But I suspect that's going to be even less well received. (Before you scream, the whole point of that is the mandatory cleanup in the end. The goto arranges it to be executed always, but still puts it out of way.)
Really, I think the code in your first snippet is fine, and the issue is with your guidelines. Even if we only write return error_code; in one place, it's not enough to guarantee that the error code saved in variable is always correct, or that the function completes all cleanup that might be required. (Consider something that allocates memory, and has to release it in any case.)

c programming optimize packet forwarder

I have written UDP packet forwarder which opens UDP port and it continuously listen on perticolar socket and when data comes to it, it forwards data to another end point.
Problem I am facing is while running process for longer duration its process eats up almost 50% of system memory and other process suffers from it.
I have use PCRE library for some regex checking but it seems like main cause of problem how can i optimize my code that can run for infinite without any memory issue.
below is my code i have use of PCRE regex and socket forwarder.
int parse(char *str){
pcre *reCompiled;
pcre_extra *pcreExtra;
int pcreExecRet;
int subStrVec[30];
const char *pcreErrorStr;
int pcreErrorOffset;
int returnval;
char *aStrRegex;
char **aLineToMatch;
const char *psubStrMatchStr;
int j;
//*aLineToMatch = str;
aStrRegex = "(.*)(\"ABC\":)(\\d+)+";
//printf("Regex to use: %s\n", aStrRegex);
// First, the regex string must be compiled.
reCompiled = pcre_compile(aStrRegex, 0, &pcreErrorStr, &pcreErrorOffset, NULL);
/* OPTIONS (second argument) (||'ed together) can be:
PCRE_ANCHORED -- Like adding ^ at start of pattern.
PCRE_CASELESS -- Like m//i
PCRE_DOLLAR_ENDONLY -- Make $ match end of string regardless of \n's
No Perl equivalent.
PCRE_DOTALL -- Makes . match newlins too. Like m//s
PCRE_EXTENDED -- Like m//x
PCRE_EXTRA --
PCRE_MULTILINE -- Like m//m
PCRE_UNGREEDY -- Set quantifiers to be ungreedy. Individual quantifiers
may be set to be greedy if they are followed by "?".
PCRE_UTF8 -- Work with UTF8 strings.
*/
// pcre_compile returns NULL on error, and sets pcreErrorOffset & pcreErrorStr
if(reCompiled == NULL) {
printf("ERROR: Could not compile '%s': %s\n", aStrRegex, pcreErrorStr);
exit(1);
} /* end if */
// Optimize the regex
pcreExtra = pcre_study(reCompiled, 0, &pcreErrorStr);
/* pcre_study() returns NULL for both errors and when it can not optimize the regex. The last argument is how one checks for
errors (it is NULL if everything works, and points to an error string otherwise. */
if(pcreErrorStr != NULL) {
printf("ERROR: Could not study '%s': %s\n", aStrRegex, pcreErrorStr);
exit(1);
}
/* Try to find the regex in aLineToMatch, and report results. */
pcreExecRet = pcre_exec(reCompiled,
pcreExtra,
str,
strlen(str), // length of string
0, // Start looking at this point
0, // OPTIONS
subStrVec,
30); // Length of subStrVec
/* pcre_exec OPTIONS (||'ed together) can be:
PCRE_ANCHORED -- can be turned on at this time.
PCRE_NOTBOL
PCRE_NOTEOL
PCRE_NOTEMPTY */
// Report what happened in the pcre_exec call..
//printf("pcre_exec return: %d\n", pcreExecRet);
if(pcreExecRet < 0) { // Something bad happened..
returnval = -1;
switch(pcreExecRet) {
case PCRE_ERROR_NOMATCH : log_message("String did not match the pattern"); break;
case PCRE_ERROR_NULL : log_message("Something was null"); break;
case PCRE_ERROR_BADOPTION : log_message("A bad option was passed"); break;
case PCRE_ERROR_BADMAGIC : log_message("Magic number bad (compiled re corrupt?)"); break;
case PCRE_ERROR_UNKNOWN_NODE : log_message("Something kooky in the compiled re"); break;
case PCRE_ERROR_NOMEMORY : log_message("Ran out of memory"); break;
default : log_message("Unknown error"); break;
} /* end switch */
} else {
//printf("Result: We have a match!\n");
// At this point, rc contains the number of substring matches found...
if(pcreExecRet == 0) {
pcreExecRet = 30 / 3;
} /* end if */
// PCRE contains a handy function to do the above for you:
for(j=0; j<pcreExecRet; j++) {
pcre_get_substring(str, subStrVec, pcreExecRet, j, &(psubStrMatchStr));
} /* end for */
returnval = atoi(psubStrMatchStr);
// Free up the substring
pcre_free_substring(psubStrMatchStr);
} /* end if/else */
// Free up the regular expression.
pcre_free(reCompiled);
// Free up the EXTRA PCRE value (may be NULL at this point)
if(pcreExtra != NULL) {
#ifdef PCRE_CONFIG_JIT
pcre_free_study(pcreExtra);
#else
pcre_free(pcreExtra);
#endif
}
return returnval;
}
-------------------Udp Listener---------------
while (1) {
n = recvfrom(sock_receiver,buf,2048,0,(struct sockaddr *)&from,&sender_length);
if (n < 0) error("recvfrom");
//write(1,"Received a datagram: ",21);
// printf("n = %d\n", n);
// printf("length of buffer = %lu\n", strlen(buf));
// write(1,buf,n);
strncpy(str, buf, n);
str[n] = '\0'; // IMPORTANT!
value = parse(str);
if(curTime != get_hour()){
//sprintf(temp_str,"Counter",minute,get_minute());
log_message("Counter reset");
reset_component_hits(components);
//reset_component_hits(dropped_msg);
curTime = get_hour();
}
if(value >=0 && components[value] < component_limit && value < max_component){
n = sendto(sock_forwarder,buf,n,0,(const struct sockaddr *)&sender,sender_length);
if (n < 0){
error("sendto");
}
components[value] = components[value]+1;
}else{
if(value < 0 ) {
error_msg = "Unable to parse component";
}else if(value >= max_component){
error_msg = "value not found in valid component list";
}else if(components[value] >= component_limit) {
error_msg = "Rate limit exceeded";
}else {
error_msg = "Message dropped for Unknown reason";
}
sprintf(temp_str,"[Component:%d] %s",value,error_msg);
log_message(temp_str);
bzero(temp_str,100);
bzero(error_msg,100);
}
// print_array(components);
// print_array(dropped_msg);
bzero(buf,2048);
bzero(str,2048);
}

Elegant error checking

Our code (in a simple library implementation) is beginning to look like this:
err = callToUnderlyingLibrary1();
if (err!=0) {
printf ("blah %d\n", err);
...
}
err = callToUnderlyingLibrary2();
if (err!=0) {
printf ("blah %d\n", err);
...
}
err = callToUnderlyingLibrary3();
if (err!=0) {
printf ("blah %d\n", err);
...
}
This is cumbersome and ugly. Is there a better way to do this ? Perhaps using the C preprocessor ? I was thinking something like:
CHECK callToUnderlyingLibrary1();
CHECK callToUnderlyingLibrary2();
CHECK callToUnderlyingLibrary3();
where the CHECK macro invokes the function and does the rudimentary error checking.
Are there preferred idiomatic ways of handling this ?
Another macro-based approach which you can use to mitigate the shortcomings in C fairly easily:
#define CHECK(x) do { \
int retval = (x); \
if (retval != 0) { \
fprintf(stderr, "Runtime error: %s returned %d at %s:%d", #x, retval, __FILE__, __LINE__); \
return /* or throw or whatever */; \
} \
} while (0)
Then to invoke it you have:
CHECK(doSomething1());
CHECK(doSomething2());
// etc.
For bonus points you could easily extend the CHECK macro to take a second argument y that is what to do on failure:
#define CHECK(x, y) do { \
int retval = (x); \
if (retval != 0) { \
fprintf(stderr, "Runtime error: %s returned %d at %s:%d", #x, retval, __FILE__, __LINE__); \
y; \
} \
} while (0)
// We're returning a different error code
CHECK(someFunction1(foo), return someErrorCode);
// We're actually calling it from C++ and can throw an exception
CHECK(someFunction2(foo), throw SomeException("someFunction2 failed")):
Usually, in C, one uses goto for error handling:
int foo()
{
if (Function1() == ERROR_CODE) goto error;
...
struct bar *x = acquire_structure;
...
if (Function2() == ERROR_CODE) goto error0;
...
release_structure(x);
return 0;
error0:
release_structure(x);
error:
return -1;
}
This can be improved with macros and more clever instruction flow (to avoid repeating cleanup code), but I hope you see the point.
I think you should look at exceptions and exception handling. http://www.cplusplus.com/doc/tutorial/exceptions/
try{
callToUnderlyingLibrary1();
callToUnderlyingLibrary2();
callToUnderlyingLibrary3();
}catch(exception& e)
//Handle exception
}
your library functions can throw exceptions if there is an error
Here is a proposition, you may or may not like it:
make your functions return 0 on failure, something else on success
if something fails in your functions, have them set a global (or static) variable to the error code (like errno)
create a die() function that prints the error depending of the error code (or whatever you want it to do)
call your functions with do_something(foo, bar) || die("Argh...");
I prefer a variant of Alexandra C.'s goto-approach:
int foo()
{
int rv = 0;
struct bar *x = NULL;
struct bar *y = NULL;
rv = Function1();
if (rv != OK){
goto error;
}
//...
x = acquire_structure();
if (x==NULL){
rv = ERROR_MEMORY;
goto error;
}
//...
rv = Function2();
if (rv != OK){
goto error;
}
//...
y = acquire_structure();
if (y==NULL){
rv = ERROR_MEMORY;
goto error;
}
//...
rv = release_structure(x);
x = NULL;
if (rv != OK){
goto error;
}
rv = release_structure(y);
y = NULL;
if (rv != OK){
goto error;
}
return OK;
error:
if (x!=NULL){
release_structure(x);
}
return rv;
}
When you use multiple goto-destinations, it is easy to mix them up. Or perhaps you move the initialization of a variable, but forget to update the gotos. And it can be very difficult to test all ways a C-method can fail.
I prefer having a single goto-destination that performs all the cleanup. I find that makes it easier to avoid mistakes.
You could do what you said, which is some rudimentary macro:
#define CHECK(x) (err = x()); \
if (err) { \
printf("blah %d on line %d of file %s\n", err, __LINE__, __FILE__); \
} \
else (void)0
And you could use it like
int err = 0;
CHECK(callToUnderlyingLibrary1); // don't forget the semicolon at the end
CHECK(callToUnderlyingLibrary2);
CHECK(callToUnderlyingLibrary3);
No 'goto', use only 1 'return' in functions. That's the elegant code.
IMHO, OP's question point and all answers are talking about FANCY techniques. Fancy code is just sort of eye candy.

Resources