Over reliance on macros

2020-07-02 08:22发布

I feel, every time I read a C or C++ program, that half or more of it is just macros. I understand that macros can be cool but they are hard to track, debug, etc. Not to mention that most programming languages do not even define something like macros (although Perl6 will have something of the sort).

I personally always have found a way to write my code without using macros, whether it be with templates, multiple inheritance, etc. I have even felt I am not a good programmer because all the pros use macros and I try to avoid them as much as I can.

The question is, are there problems which cannot be solved without macros? Are macros ultimately a good/bad practice? When should I consider using a macro?

标签: c++ c macros
13条回答
我欲成王,谁敢阻挡
2楼-- · 2020-07-02 09:02

I tend to avoid using macros as much as possible because of their obvious safety / debugging issues, however there are times when macros offer something that no other facility within the language does as elegantly, in which case I prefer to use a macro just because it makes my life (and those of my fellow developers) easier.

For example, I have created an Enum class, which wraps an enum in a struct (scope) and adds some functionality:

  • possibility of iteration (which implies an order of the values)
  • conversion to / from string (handy to read/write to a file, write to logs)

In order to create the enum, I use a macro which will automatically generate the converter (to and from) and the vector for iteration.

Of course I could do without one, after all the macro is only for code generation. But doing without one would mean violating DRY, and in my little own preferences "DRY" > "Don't use macros". Because once debugged the macro is safe, whereas a DRY violation is a nightmare for maintenance.

Now, I am all for ditching this macro as soon as I find how not to violate DRY. Ideas are obviously welcome... and an external script is NOT better ;)

My 2 cents.

查看更多
地球回转人心会变
3楼-- · 2020-07-02 09:05

The question is, are there problems which cannot be solved without macros?

No.

are macros ultimately a good/back practice? When should I consider to use a macro?

In languages which don't support or honor the inline keyword, macros are a great way to re-use code, but at the same time avoid the overhead of a function call in any code that is tightly looped enough for that to make a huge difference.

Your rant about code being littered with macros is probably justified. There are indeed hard to debug and in some cases to read. But they do come in useful in the very small number of cases where optimisation like this is truly warranted.

Note that as of C99, C can now do explicit inline functions using the inline keyword, which reduces the need for macros and even has advantages over using macros.

查看更多
Melony?
4楼-- · 2020-07-02 09:07

Yes, here's one. When you need to add tracing code to your program in such a way that one configuration contains it and the other completely omits you have to use macros.

Something like:

#ifdef WITH_LOGGING
    #define LOG( x ) DoLog( x )
#else
    #define LOG( x )
#endif

now you use it this way:

LOG( L"Calling blahblahblah with " + getSomeStringHardToCompute() );

and in the configuration with WITH_LOGGING you have that code and otherwise it is completely omitted - not even present in the binary, and therefore

  • it doesn't help others analyze your program
  • you get a smaller binary
  • the program doesn't waste time fo logging at all
  • the compiler can produce better optimized code.
查看更多
倾城 Initia
5楼-- · 2020-07-02 09:08

Debug behaviour may be controlled with constant flags or debug functions. So here is my list of unavoidables:

  • Multiple inclusion protection.
  • Macros are the only way of symbol stringification. assert macro, compact realization of const string & stringify(enum category value);

Example:

const char* stringify(enum category value)
{
    #define c(x) case x: return #x;
    switch(value) {
        c(CIRCLE)
        c(RECTANGLE)
        c(TRIANGLE)
        default: return "UNKNOWN";
    }
    #undef c // the most important part
}
查看更多
疯言疯语
6楼-- · 2020-07-02 09:08

I think that C++'s templates and inline functions make macros pretty much avoidable.

The ubiquitousness of macros is probably due to the fact that there are many C++ programmers that used to be C programmers. Such people will probably be proficient at using macros (because it sometimes really is the best or only solution in pure C) and might not see any point in learning the more complicated C++ features if they already know how to solve the problem. At least in the open source world, there are many C converts, so you naturally meet C paradigms. I don't think that you're a bad programmer if you avoid such a feature, many people do, just like GOTOs.

C (and therefore C++) is an extremely flexible programming language. This is great, because everyone can develop his own distinct style and solve most problems in several different ways. This, however, can also be considered a problem. In my opinion not a problem that should be solved by the language but by establishing conventions.

There are many features in C++ that can be safely ignored. Maybe there are weird special occasions where such a feature would really be the best approach, but in most cases, you can live without:

  • Friend classes
  • Macros
  • GOTOs And more.

IMO, a senior C++ programmer should be able to at least read them all fluently - yet I expect a good programmer to consider carefully when and if to use an infamous feature.

查看更多
迷人小祖宗
7楼-- · 2020-07-02 09:08

Macros are a solution for conditional compiling (by ifdef and ifndef). Here is the examples:

1)

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP

//...

#endif

2)

#ifdef __cplusplus
#define BEGIN extern "C" {
#define END }
#define NULL (0);
#else
#define BEGIN
#define END
#define NULL ((void*)0);
#endif

//-------------------------

BEGIN

void my_function(char* str);

END

//-------------------------

void my_function(char* str)
{
    if(str != NULL)
    {
        //...
    }
}

But inline functions and templates replaces other usages of macros in C++.

查看更多
登录 后发表回答