Solved

C++ Inline fucntion vs. macro

Posted on 2004-03-30
10
36,439 Views
Last Modified: 2011-08-18
hello.
Please, what is difference between an inline function and a macro in C++ since both are expanded in-line.
waiting..
thanks.
0
Comment
Question by:soodsandeep
  • 3
  • 3
  • 2
  • +2
10 Comments
 
LVL 33

Expert Comment

by:hongjun
ID: 10721129
The difference is in interpreting arguments. Arguments for inline functions are typed, therefore compiler can apply some type checking to that function calls.
Macro isn't type checked and does not evaluate arguments, but simply takes the string passed to the macro and replace each occurence of macro argument in the text of macro with actual string for that parameter. It may give you sometimes very surpising results. For instance macro:
   #define  MAX(x,y)  ((x)>(y)?(x):(y))
when called like this:
   y = 2;
   x = 2;
   x = MAX(++x, y);
will return 4! not 3, because in the code the macro is expanded to:
   x = ((++x)>(y)?(++x):(y))

If you define inline function for that purpose the result will be 3.
   inline int Max(int x, int y)
   {
      return x>y?x:y;
   }
0
 
LVL 33

Expert Comment

by:hongjun
ID: 10721131
There are other differences too.  For example, macro's do not obey scope properly, so if you declare a MAX() in a namespace or in a class, the macro will replace invokations of this MAX.  This either results in a compiler error incorrect behavrior.

There is nearly no justifiable reason to use macros in C++.  Any use of macros is risky, as PMazur's example and mine both illistrate.  C++ provides alternatives, like inline functions and templates.  These can replace nearly every use of macros, but will be safer and more powerful.

Do yourself a favor, forget macros exist.
0
 
LVL 33

Expert Comment

by:hongjun
ID: 10721135
There is another, possibly more significant difference. The (pre) compiler will replace every occurrence of the macri name with the defined tokenstring. IOW suppose you defined:

#define max(a,b) ((a)>(b)?(a):(b))

every occurence of max() will be replaced with (or attempted to be replaced with) the macro definition.
0
 
LVL 45

Accepted Solution

by:
sunnycoder earned 100 total points
ID: 10721167
Hi soodsandeep,

1. macros are processed by the preprocessor while inline functions are processed by the compiler
2. for macros the code is literally copied into the location it was called from. So if the user passes a "double" instead of an "int" then problems could occur. However, if this senerio happens with an inline function the compiler will complain about incompatible types.
3. macros are marginally faster

Sunnycoder
0
 
LVL 14

Expert Comment

by:wayside
ID: 10723595
Unlike a function, macros don't have to be compileable units.

For example:

#define START_LOOP (x,y) while ((x) < (y)) {

#define END_LOOP  }

Then I can do

int a=5, b=10;

START_LOOP(a,b)
// do fun stuff here
myfunc(a);
END_LOOP

This is a trivial example, but START_LOOP could be a very complicated expression.

A more sophisticated example:

#if !defined(_DEBUG) && !defined(DEBUG)
#define HANDLE_ERROR_BEGIN  int checkpoint = 0; try {
#define HANDLE_ERROR_END(x) } catch (Error* e) { \
                                            e->Push(checkpoint, x); \
                                            throw(e); } \
                               catch (...) { Error* e = new Error; \
                                            e->Push(checkpoint, x); \
                                            throw(e); }
#else
#define HANDLE_ERROR_BEGIN int checkpoint = 0;
#define HANDLE_ERROR_END(x)
#endif

You would use this like this:

int myfunc()
{
  HANDLE_ERROR_BEGIN
  int a;
  myotherfunc(a);
  // etc

 HANDLE_ERROR_END("int myfunc")
}

This allows me to trap errors in release mode, but it debug it doesn't trap them so I can debug it.

Final example -if you do any MFC programming, take a look at the definitions of BEGIN_MESSAGE_MAP/END_MESSAGE_MAP.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 5

Expert Comment

by:jerry_jeremiah
ID: 10730476
One big difference:  If you have a bunch of code in a macro and you are debugging your program and you come into a function like:

CS_RETCODE inv_rpc(VOIDPTR UNUSED(ptr), DBPROCESS *dbproc,
                char *rpc_name, DB_RPC_PARAM *rpc_params, ...)
{
    LOCAL_VARIABLE_DECLARATIONS
    SET_RETRY_CONFIG_VARIABLES
    for (counter = 0; counter < rpc_retry_count; counter++) {
        SET_UP_QUERY
        while (dbresults(dbproc) != NO_MORE_RESULTS)
            dbcanquery(dbproc);
        PROCESS_RETURN_INFO
    }
    CHECK_RETURN_STATUS
    return CS_SUCCEED;
}

The debugger can't see inside the macros because it isn't actual code in the executable so it jumps over it and then how do you know that the code is doing the right thing?

Not being able to debug inside macros is the very worst thing to have happen when you have a service level agreement guaranteeing less than 14 minutes of downtime a month (honestly, that's what my SLA says!)

That code above is right out of actual production code that I have to support.  Here is what one of those macros actually looks like.  I just have one question - would you not want the ability to debug into this code?

#define PROCESS_RETURN_INFO \
        if ((ret_param_num = dbnumrets(dbproc)) > 0) { \
            va_start(param_list, rpc_params); \
            for (param_ptr = rpc_params;  \
                    param_ptr->paramname != END_PARAM_TABLE; param_ptr++) { \
                param_val = va_arg(param_list, CS_BYTE *); \
                if (param_ptr->status == (CS_BYTE) DBRPCRETURN) { \
                    for (i=1; i <= ret_param_num; i++) { \
                        if (strcmp(dbretname(dbproc, (int) i),  \
                                param_ptr->paramname) == 0) { \
                            return_val = dbretdata(dbproc, (int) i); \
                            len = dbretlen(dbproc, (int) i); \
                            for (j = 0; j < len; j++) \
                                param_val[j] = return_val[j]; \
                            if (param_ptr->maxlen != -1) \
                                param_val[j] = '\0'; \
                            if (param_ptr->type == SYBCHAR) { \
                                while (param_val[--j] == ' ' && j >= 0) \
                                    param_val[j] = '\0'; \
                            } \
                            break; \
                        } \
                    } \
                } \
            } \
            va_end(param_list); \
        } \
 \
        if (dbhasretstat(dbproc)) { \
            ret_stat = dbretstatus(dbproc); \
            switch (ret_stat) { \
                case PROC_SUCCESS_STATUS: \
                    return CS_SUCCEED; \
 \
                case PROC_DEADLOCK_VICTIM: \
                    ASC_event("SYS_WARN", __LINE__, __FILE__, \
                        "Warning! RPC DeadLock Victim, Ret Stat %d, Retry %d", \
                         ret_stat, counter); \
                    ASC_sleep(rpc_retry_sleep); \
                    continue; \
 \
                case PROC_RESOURCE_ERR: \
                    ASC_event("RPCSPACE", __LINE__, __FILE__,  \
                        "Critical Resource Error; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_MISSING_OBJECT: \
                    ASC_event("RPC_ERR", __LINE__, __FILE__,  \
                      "Error: Missing RPC Object; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_DATATYPE_ERR: \
                    ASC_event("RPC_ERR", __LINE__, __FILE__,  \
                        "RPC Datatype Error; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_PERMISSION_ERR: \
                    ASC_event("RPC_ERR", __LINE__, __FILE__,  \
                        "RPC Permission Error; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_SYNTAX_ERR: \
                    ASC_event("RPC_ERR", __LINE__, __FILE__,  \
                        "RPC Syntax Error; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_MISC_ERR: \
                    ASC_event("RPC_ERR", __LINE__, __FILE__,  \
                        "Misc User RPC Error; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_NON_FATAL_INT_ERR: \
                    ASC_event("RPC_ERR", __LINE__, __FILE__,  \
                      "Non Fatal Internal Error; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_SYS_LIMIT_ERR: \
                    ASC_event("RPCSPACE", __LINE__, __FILE__,  \
                        "System Limit Reached; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_FATAL_INCON1: \
                case PROC_FATAL_INCON2: \
                    ASC_event("RPCSPACE", __LINE__, __FILE__,  \
                     "Error: Fatal Inconsistency; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_CORRUPT_TBL_IDX: \
                    ASC_event("RPCSPACE", __LINE__, __FILE__,  \
                      "RPC - Corrupt Table/Index; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_CORRUPT_DATABASE: \
                    ASC_event("RPCSPACE", __LINE__, __FILE__,  \
                        "RPC - Corrupt DataBase; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                case PROC_HARDWARE_ERR: \
                    ASC_event("RPCSPACE", __LINE__, __FILE__,  \
                        "RPC - Hardware Error; Sleeping %d Mins, Retry %d", \
                         rpc_error_sleep/60, counter); \
                    ASC_sleep(rpc_error_sleep); \
                    continue; \
 \
                default: \
                    ASC_event("RPC_ERR", __LINE__, __FILE__,  \
                      "Error: Unknown RPC Error [%d] - Failing RPC",ret_stat); \
                    return CS_FAIL; \
            } \
        } \
        else \
            return CS_SUCCEED;

#define SET_UP_QUERY \
 \
        ASC_diag(NULL, KERNEL_LEVEL, "Invoke RPC", __LINE__, __FILE__, \
            "Invoking RPC %s, using DBPROC @ %08X", rpc_name, dbproc); \
 \
        start = ASC_cur_tm(); \
        dbrpcinit(dbproc, rpc_name, (CS_SMALLINT)0); \
        if (rpc_params != NULL) { \
            va_start(param_list, rpc_params); \
            for (param_ptr = rpc_params; \
                    param_ptr->paramname!= END_PARAM_TABLE; param_ptr++) { \
                param_val = va_arg(param_list, CS_BYTE *);  \
                if (param_ptr->datalen == 1) \
                    len = 1; \
                else \
                    len = (param_ptr->type == SYBCHAR)?  \
                        strlen((char *) param_val): param_ptr->datalen; \
                if (dbrpcparam(dbproc, param_ptr->paramname, \
                        param_ptr->status, param_ptr->type, param_ptr->maxlen, \
                        len, param_val) == CS_FAIL) { \
                    ASC_event("RPC_ERR", __LINE__, __FILE__, \
                        "Error: %s dbrpcparam(%s) Failed",  \
                         rpc_name, param_ptr->paramname); \
                    return CS_FAIL; \
                } \
            } \
            va_end(param_list); \
        } \
        if (dbrpcsend(dbproc) == CS_FAIL) { \
            ASC_event("RPC_ERR", __LINE__, __FILE__, \
                "Error: dbrpcsend(%s) Failed", rpc_name); \
            return CS_FAIL; \
        } \
        if (dbsqlok(dbproc) == CS_FAIL) { \
            ASC_event("RPC_ERR", __LINE__, __FILE__, \
               "Error: dbsqlok(%s) Failed", rpc_name); \
            return CS_FAIL; \
        } \
        end = ASC_cur_tm(); \
        if (strcmp(rpc_name, "kick_start") != 0) { \
            ASC_diag(NULL, LOW_LEVEL, "Invoke RPC", __LINE__, __FILE__,  \
               "Success: dbsqlok (%s) succeeded in %.0fms",  \
                rpc_name, MS_DIFF(start, end)); \
        }

Worse yet, these aren't the only ones - there are a whole bunch of these things!  And don't tell me to change the code.  I support the app - I do not enhance it...

Jerry
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10730573
jerry_jeremiah,

For that much long code, you have little options left ;o) ... you have to use macros ... most compilers will not make that big a code as inline even if you specify them as inline.

Some compilers can let you see into macros (e.g. gdb with code compiled at 3rd level using gcc) ... however I am not sure if it allows stepping through that big a macro... so capacity is quite limited indeed
0
 
LVL 14

Expert Comment

by:wayside
ID: 10731514
Faced with debugging stuff like jerry_jeremiah's, I'd be tempted to set up my build environment to preprocess first, then build the preprocessed files. Then you could debug them...

That's definitely macro abuse. Exapanding every function out to a couple hundred lines of code must lead to incredible code bloat.
0
 

Author Comment

by:soodsandeep
ID: 10738216
Thanks for all the replies.
but one by Sunnycoder suited me best.
SunnyCoder, Please as you have written "..Macros are faster.."
But why macros are faster than functions(inline).


Thanks TO all again.
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10738614
I would like to stress that they are just marginally faster .... My source of information had derived this conclusion emperically ...

C++ faq offers some information
http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.3

0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
PL/SQL help needed. Script to compare columns and copy data between tables 6 58
pre4 challenge 19 88
countX 22 70
How To Loop - Python 19 67
How to remove superseded packages in windows w60 or w61 installation media (.wim) or online system to prevent unnecessary space. w60 means Windows Vista or Windows Server 2008. w61 means Windows 7 or Windows Server 2008 R2. There are various …
If you haven’t already, I encourage you to read the first article (http://www.experts-exchange.com/articles/18680/An-Introduction-to-R-Programming-and-R-Studio.html) in my series to gain a basic foundation of R and R Studio.  You will also find the …
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now