Writing a #define for a common statement

Often when I program in C I write the expression for (int i = 0; i < j; i++).

I never wrote a macro or a define expression, but could I write a #define to simplify the above expression so that do i,j gets pre-processed to for (int i = 0; i < j; i++) ? Or, is it for some reason not a good idea?

3

Don’t do this.

Using macros to reconfigure the language like this is like writing in slang. One or two instances might not seem so bad to someone has to read it (including yourself) but every time you do it you make it that much more likely that the ‘well what does that mean’ effect happens. You’re needlessly obscuring your code, adding a layer of mental work necessary to write/read/reason about it, and that’s never good.

In addition, macros defined via the preprocessing mechanism can be touchy in terms of what they do, in a way that can lead to bugs that will make you tear your hair out.

For example a macro that defines ‘forloop(i, j)’ to something like ‘for (int i = 0; i < j; i++)’ might tempt you to one day write ‘forloop(i, j++)’. What would you expect j to be after the loop?

There are usually ways around that, but it’s better and easier in the long run to just avoid the problem altogether.

To answer your question, yes you could write a macro to accomplish the for loop. However, this is not a very good idea. As another user pointed out, this adds difficulty in understanding the program.

Also, I have seen first hand where this can become a problem. I once witnessed a situation where a contractor used 4 or 5 levels of macros on top of one another. After they completed the assignment, we ended up dumping off all of the code and starting from scratch rather than trying to re-use the code.

If you really feel like you only want to stream-line writing code that does things like for-loops, just create a simple function.

Here are some of the proper ways to use macros (if you must use a macro):

The definition of your header files (the once-only method). Often you will want to ensure that the header file is only pre-processed a single time on compilation, so that as your program grows large you will not get build errors. This can be done the following way (see more information here):

#ifndef HEADER_FILE_H
#define HEADER_FILE_H

/* your header file code here */

#endif HEADER_FILE_H

Then, another proper way to use macros is when you need to specify a memory location that you don’t want to represent as hexadecimal all over your program. This is especially common when writing low-level C-code for micro-controllers or microprocessors. You want your users to see something like LED_PIN_ADDR instead so others will know that it’s the address of the pin location with the LED attached. It can be done in the following way:

#define LED_PIN_ADDR 0x0123ABCD

One of the best rules of thumb in such situations is a famous phrase: “Code is read more often than it is written.” You’re going to write the code once. It’s not that big of a deal to type a few more characters.

When starting use macros, the question should be “does this make it easier for the reader to understand.” The answer to that question depends very much on the reader, but in general you will find that macros decrease readability.

Macros increase readability when they turn something that’s hard to read into something that’s easy to read. For example, some of the code I work with has a macro CATCH_AND_HANDLE_TYPICAL_EXCEPTIONS which is a block of boilerplate about 20 lines long which gets used dozens of times. For our developers at our company, that particular macro improves readability. It decreases the amount of time the reader spends hung up on working through the details of exception handling.

Writing readable macros is an art. If you are new to C, I would recommend avoiding writing them for a while, just so you can get used to what others find readable and unreadable. Then, once you’re ready, start by learning key macro idioms like the do { ... } while(0) idiom, which makes a macro act more like a statement. It’s a crawl, walk, run process.

Then, if you choose to learn C++ also, take a look at Boost.Preprocessor. It will show you just how absurdly powerful macros are… and why you should never want to turn to the dark side and use them like they do in that library =)

(I’ve turned to the darkside of BOOST_PP twice in my career. One was a complete mistake. The other… unclear)

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *