Why have they done this?
-
So I'm going through the source code for the Log4CPlus logging library and found this snippet:
#define LOG4CPLUS_DEBUG(logger, logEvent) \ do { \ if(logger.isEnabledFor(log4cplus::DEBUG_LOG_LEVEL)) { \ log4cplus::tostringstream _log4cplus_buf; \ _log4cplus_buf << logEvent; \ logger.forcedLog(log4cplus::DEBUG_LOG_LEVEL, _log4cplus_buf.str(), __FILE__, __LINE__); \ } \ } while(0);
This of course logs a given string to the active logging class. The question is why have they wrapped all that in a do-while loop? If you look at the loop, it will only be called once (while(0)). Is this some kind of preventitive measure to ensure that the compiler or optimiser does not strip the macro code out?
I Dream of Absolute Zero
-
So I'm going through the source code for the Log4CPlus logging library and found this snippet:
#define LOG4CPLUS_DEBUG(logger, logEvent) \ do { \ if(logger.isEnabledFor(log4cplus::DEBUG_LOG_LEVEL)) { \ log4cplus::tostringstream _log4cplus_buf; \ _log4cplus_buf << logEvent; \ logger.forcedLog(log4cplus::DEBUG_LOG_LEVEL, _log4cplus_buf.str(), __FILE__, __LINE__); \ } \ } while(0);
This of course logs a given string to the active logging class. The question is why have they wrapped all that in a do-while loop? If you look at the loop, it will only be called once (while(0)). Is this some kind of preventitive measure to ensure that the compiler or optimiser does not strip the macro code out?
I Dream of Absolute Zero
-
For an answer, please see: http://c-faq.com/cpp/multistmt.html[^]
-
So I'm going through the source code for the Log4CPlus logging library and found this snippet:
#define LOG4CPLUS_DEBUG(logger, logEvent) \ do { \ if(logger.isEnabledFor(log4cplus::DEBUG_LOG_LEVEL)) { \ log4cplus::tostringstream _log4cplus_buf; \ _log4cplus_buf << logEvent; \ logger.forcedLog(log4cplus::DEBUG_LOG_LEVEL, _log4cplus_buf.str(), __FILE__, __LINE__); \ } \ } while(0);
This of course logs a given string to the active logging class. The question is why have they wrapped all that in a do-while loop? If you look at the loop, it will only be called once (while(0)). Is this some kind of preventitive measure to ensure that the compiler or optimiser does not strip the macro code out?
I Dream of Absolute Zero
because it provides a bloc of code... simply.
TOXCCT >>> GEII power
[VisualCalc 3.0 updated ][Flags Beginner's Guide new! ]
-
The reason given in that article is actually pretty poor. Yes, it forces the programmer to use a trailing semi-colon, but that isn't necessary (mostly, they do that simply for looks). The real reason for enclosing it in a do-while loop is to prevent naming conflicts. For example, lets say you have the following macro:
#define SWAP_INT(a, b) \ int c = a; \ a = b; \ b = c;
Now, your code looks something like the following:void main() { int a = 1, b = 2, c = 0; SWAP_INT(a, b); // compiler-error! c is declared multiple times }
This creates a hard to find compiler-error that will annoy you (and anyone else trying to use that macro with a variable named 'c'). To prevent this, you could use the scoping operator:#define SWAP_INT(a, b) \ { \ int c = a; \ a = b; \ b = c; \ }
However, some older C++ compilers do not treat this correctly (or even handle it at all. Thus, you can create a single loop do-while to handle the scoping:#define SWAP_INT(a, b) \ do { \ int c = a; \ a = b; \ b = c; \ } while (0);
The trailing ; is purely optional. If you leave it off, you force the programmer to place it themselves (thus treating it like a function call). Putting it there doesn't hurt anything though. As a side note, declaring it the way they did (as a macro) is poor programming practice. It really should have been declared as a function. If the user passes an int as the "logger", they will get some weird compiler error messages dealing with types and unless they search through the code to find the macro defintion, will have no idea why it is happening. If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac -- modified at 11:53 Thursday 1st June, 2006 -
The reason given in that article is actually pretty poor. Yes, it forces the programmer to use a trailing semi-colon, but that isn't necessary (mostly, they do that simply for looks). The real reason for enclosing it in a do-while loop is to prevent naming conflicts. For example, lets say you have the following macro:
#define SWAP_INT(a, b) \ int c = a; \ a = b; \ b = c;
Now, your code looks something like the following:void main() { int a = 1, b = 2, c = 0; SWAP_INT(a, b); // compiler-error! c is declared multiple times }
This creates a hard to find compiler-error that will annoy you (and anyone else trying to use that macro with a variable named 'c'). To prevent this, you could use the scoping operator:#define SWAP_INT(a, b) \ { \ int c = a; \ a = b; \ b = c; \ }
However, some older C++ compilers do not treat this correctly (or even handle it at all. Thus, you can create a single loop do-while to handle the scoping:#define SWAP_INT(a, b) \ do { \ int c = a; \ a = b; \ b = c; \ } while (0);
The trailing ; is purely optional. If you leave it off, you force the programmer to place it themselves (thus treating it like a function call). Putting it there doesn't hurt anything though. As a side note, declaring it the way they did (as a macro) is poor programming practice. It really should have been declared as a function. If the user passes an int as the "logger", they will get some weird compiler error messages dealing with types and unless they search through the code to find the macro defintion, will have no idea why it is happening. If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac -- modified at 11:53 Thursday 1st June, 2006 -
The reason given in that article is actually pretty poor. Yes, it forces the programmer to use a trailing semi-colon, but that isn't necessary (mostly, they do that simply for looks). The real reason for enclosing it in a do-while loop is to prevent naming conflicts. For example, lets say you have the following macro:
#define SWAP_INT(a, b) \ int c = a; \ a = b; \ b = c;
Now, your code looks something like the following:void main() { int a = 1, b = 2, c = 0; SWAP_INT(a, b); // compiler-error! c is declared multiple times }
This creates a hard to find compiler-error that will annoy you (and anyone else trying to use that macro with a variable named 'c'). To prevent this, you could use the scoping operator:#define SWAP_INT(a, b) \ { \ int c = a; \ a = b; \ b = c; \ }
However, some older C++ compilers do not treat this correctly (or even handle it at all. Thus, you can create a single loop do-while to handle the scoping:#define SWAP_INT(a, b) \ do { \ int c = a; \ a = b; \ b = c; \ } while (0);
The trailing ; is purely optional. If you leave it off, you force the programmer to place it themselves (thus treating it like a function call). Putting it there doesn't hurt anything though. As a side note, declaring it the way they did (as a macro) is poor programming practice. It really should have been declared as a function. If the user passes an int as the "logger", they will get some weird compiler error messages dealing with types and unless they search through the code to find the macro defintion, will have no idea why it is happening. If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac -- modified at 11:53 Thursday 1st June, 2006An excellent explaination! However, I will offer one more use of the
do/while(0)
block. I have seen it used as a way to providegoto
-like functionality without actually using the wordgoto
. For example, if you needed to jump out of the middle of the block, simply executing abreak
will take you to the bottom of the block, simulating agoto
to a label at the end of the block. It was a bit confusing the first time I saw code that used thedo/while(0)
like that... [Edit: Note, I do not do this myself, and would use (and have used) used agoto
in place of something like that...] Peace! -=- James
If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong!
Avoid driving a vehicle taller than you and remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road!
DeleteFXPFiles & CheckFavorites (Please rate this post!) -
An excellent explaination! However, I will offer one more use of the
do/while(0)
block. I have seen it used as a way to providegoto
-like functionality without actually using the wordgoto
. For example, if you needed to jump out of the middle of the block, simply executing abreak
will take you to the bottom of the block, simulating agoto
to a label at the end of the block. It was a bit confusing the first time I saw code that used thedo/while(0)
like that... [Edit: Note, I do not do this myself, and would use (and have used) used agoto
in place of something like that...] Peace! -=- James
If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong!
Avoid driving a vehicle taller than you and remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road!
DeleteFXPFiles & CheckFavorites (Please rate this post!)And in situations like that, exactly, I favor the goto - at least I know what is going on logically. The do{ }while(0); crap I really have to think about for a minute - to realize they just did not want to use the goto. People that start writing code immediately are programmers (or hackers), people that ask questions first are Software Engineers - Graham Shanks
-
An excellent explaination! However, I will offer one more use of the
do/while(0)
block. I have seen it used as a way to providegoto
-like functionality without actually using the wordgoto
. For example, if you needed to jump out of the middle of the block, simply executing abreak
will take you to the bottom of the block, simulating agoto
to a label at the end of the block. It was a bit confusing the first time I saw code that used thedo/while(0)
like that... [Edit: Note, I do not do this myself, and would use (and have used) used agoto
in place of something like that...] Peace! -=- James
If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong!
Avoid driving a vehicle taller than you and remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road!
DeleteFXPFiles & CheckFavorites (Please rate this post!)James R. Twine wrote:
An excellent explaination! However, I will offer one more use of the do/while(0) block. I have seen it used as a way to provide goto-like functionality without actually using the word goto. For example, if you needed to jump out of the middle of the block, simply executing a break will take you to the bottom of the block, simulating a goto to a label at the end of the block. It was a bit confusing the first time I saw code that used the do/while(0) like that...
People that code like that do so for job-security. You should NEVER do that. If you actually look at the assembly code produced by the compiler when you write a do-while(0) with a break instead of just using goto, you'll notice it is exactly the same as when you do write a goto. Although, your reasoning does offer another good reason for making this a function instead of a macro. Instead of a goto or break, you just return if you get to a state that needs such. Much cleaner, and you won't have someone asking you what the heck you are doing when they have to maintain your code. If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac