The advantage of macros in a stream in C ++

We know that in-lines are favorable because they are checked by the compiler, and the same operation (for example, ++ x) is not evaluated more than once when passed as an argument compared to macros.

But in an interview I was asked specific advantages or circumstances when a macro is more favorable for the built-in in C ++.

Does anyone know the answer or might think about this question?

+7
source share
9 answers

The only thing I can think of is some tricks that you can do with a macro that cannot be done with the built-in function. Inserting tokens together at compile time and such hacking.

+14
source

Here is a specific situation where macros are not only preferable, but in fact this is the only way to achieve something.

If you want to write a logging function that records not only a message, but also the file and line number where the instance occurred, you can directly call your function by directly entering the file and lines (or macros)

LogError("Something Bad!", __FILE__, __LINE__); 

... or, if you want it to work automatically, you must rely on a macro (warning: not compiled):

 #define LogErrorEx(ERR) (LogError(ERR, __FILE__, __LINE__)) // ... LogErrorEx("Something Else Bad!"); 

This cannot be achieved using templates, default parameters, a default construct, or any other C ++ device.

+8
source

Sometimes you want to expand the language in a way that is impossible with any other method.

 #include <iostream> #define CHECK(x) if (x); else std::cerr << "CHECK(" #x ") failed!" << std::endl int main() { int x = 053; CHECK(x == 42); return 0; } 

Prints CHECK(x == 42) failed! .

+4
source

In C ++ in particular, one use of MACRO macros that seem to pop up very often (except for debugging printing with a file and line) is to use MACRO to populate a set of standard methods in a class that cannot be inherited from the base class. In some libraries that create custom RTTI mechanisms, serialization, expression patterns, etc., they often rely on a set of static constant variables and static methods (and perhaps special semantics for some overloaded operators that cannot be inherited) that are almost always are but they must be added to any class that the user defines in this structure. In these cases, MACROs are often provided in such a way that the user does not need to worry about putting all the necessary code (he only needs to call MACRO with the required information). For example, if I create a simple RTTI (Run-Time Type Identification) identification system, I can require that all classes have a TypeID and be dynamically disabled:

 class Foo : public Bar { MY_RTTI_REGISTER_CLASS(Foo, Bar, 0xBAADF00D) }; #define MY_RTTI_REGISTER_CLASS(CLASSNAME,BASECLASS,UNIQUEID) \ public:\ static const int TypeID = UNIQUEID;\ virtual void* CastTo(int aTypeID) {\ if(aTypeID == TypeID)\ return this;\ else\ return BASECLASS::CastTo(aTypeID);\ }; 

The above cannot be done using templates or inheritance, which makes life easier for the user and avoids code repetition.

I would say that this use of MACROs is the most common in C ++.

+1
source

As already mentioned, macros can use, for example, preprocessor directives: __FILE__ , __LINE__ , but, of course, #include and #define can also be useful for parameter behavior:

 #ifdef __DEBUG__ # define LOG(s) std:cout << s << std:endl #else # define LOG(s) #endif 

Depending on the user, __DEBUG__ is determined whether or not (via #define or through compiler options) the LOG macro will be active or not. This is an easy way to have debugging information in all code that can be easily deactivated.

You might also consider changing the way memory is allocated ( malloc will be overridden to assign a memory pool instead of a standard heap, for example, etc.).

+1
source

Built-in functions, as the name indicates, are limited to functional tasks, the execution of some code.

Macros have a much wider application that they can expand, for example, into declarations or replace entire language constructs. Some examples (written for C and C ++) that cannot be performed using functions:

 typedef struct POD { double a; unsigned b } POD; #declare POD_INITIALIZER { 1.0, 37u } POD myPOD = POD_INITIALIZER; #define DIFFICULT_CASE(X) case (X)+2 :; case (X)+3 #define EASY_CASE(X) case (X)+4 :; case (X)+5 switch (a) { default: ++a; break; EASY_CASE('0'): --a; break; DIFFICULT_CASE('A'): a = helperfunction(a); break; } #define PRINT_VALUE(X) \ do { \ char const* _form = #X " has value 0x%lx\n"; \ fprintf(stderr, _form, (unsigned long)(X)); \ } while (false) 

In the context of C ++, Boost has many examples that are more attractive and useful.

But since with such macros you somehow expand the language (not necessarily, the preprocessor is part of it), many people do not like macros, especially in the C ++ community, a little less in the C community.

In any case, if you use such constructions, you should always be very clear about what you need to achieve, to document well and to fight the temptation to confuse your code.

+1
source

A macro is exactly the same as a text replacement definition.

These are the significant differences that come to my mind:

  • It does not have to be functional. I mean that it does not have to contain some consistent set of brackets, for example.
  • It can be used elsewhere. As in the field of class declarations or even in the global field. Therefore, this should not be within the scope of another function.

You must use them if you want to perform actions that cannot be performed using functions:

  • initialization of complex tables (makes reading more understandable)
  • facilitating the declaration of some special members, such as event identifiers or tags (much used in MFC IMPLEMENT_DYNAMIC)
  • compress duplicate ads at the beginning of functions
  • already mentioned use of __LINE__ , __FILE__ , ... for logging
0
source
  #include <stdio.h> #define sq(x) x*x int main() { printf("%d", sq(2+1)); printf("%d", sq(2+5)); return 0; } 

The output for this code is 5 and 17. Macros expand throughout the text. Its not similar functions.

Explanation for this example:

sq (2 + 1) = 2 + 1 * 2 + 1 = 2 + 2 + 1 = 5

sq (2 + 5) = 2 + 5 * 2 + 5 = 2 + 10 + 5 = 17

0
source

I would add two uses:

  • MIN and MAX , before C ++ 0x, since the return type had to be declared manually, mixed MIN and MAX , because the built-in functions would be nightmare, while a simple macro did it in no time.
  • confidentiality : you can always undef macro before exiting your header, you cannot β€œdecompile” an inline function (or other symbol). This is due to the lack of proper modularity in C and C ++.
-one
source

All Articles