Dan
Dan

Reputation: 221

C - make #define 'return' a value

Lets say I have define like this:

#define CrWinDef(a,b,c,d,e,f,g,h,i,j,k,l)\
{\
    HWND thw=CreateWindowEx(a,b,c,d,e,f,g,h,i,j,k,l);\
    SendMessage(thw, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)true);\
}

Now in my code I'd like to use variable 'thw'. Using just

CrWinDef(...);

works.

However if add return thw; to my define and try to use same value in code it won't compile.

#define CrWinDef(a,b,c,d,e,f,g,h,i,j,k,l)\
    {\
        HWND thw=CreateWindowEx(a,b,c,d,e,f,g,h,i,j,k,l);\
        SendMessage(thw, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)true);\
return thw;\
    }

And in code

 HWND hwnd = CrWinDef(...);

Upvotes: 0

Views: 4406

Answers (6)

Beta512
Beta512

Reputation: 1

You can actually have a #define that returns a value:

    #define AddOne(x) ({int _temp_; _temp_ = (x) + 1; _temp_;})
      -> returns _temp_

This illustrates why this can be useful:

    #define MaxIntNotsogood(x,y) ((x) > (y) ? (x) : (y))
    c = MaxIntNotsogood(a++, b--); 
      -> expands to: c = (a++ > b-- ? a++ : b--);
      -> one of the variables gets incremented or decremented twice.

This works more reliably:

    #define MaxIntBetter(x,y) ({int _x_, _y_; _x_ = (x); _y_ = (y); _x_ > _y_ ? _x_ : _y_;})
    c = MaxIntBetter(a++, b--); 
      -> expands to: c = ({int _x_, _y_; _x_ = (a++); _y_ = (b--); _x_ > _y_ ? _x_ : _y_;});
      -> each of the variables is used only once

A useful define to return a swapped integer for ARM:

    #define SWAP32X_RV(x)   ({int32_t _temp_; __ASM volatile ("rev %0, %1" : "=r" (_temp_) : "r" (x)); _temp_;})
      -> returns a byte swapped int as a value

Upvotes: 0

ApproachingDarknessFish
ApproachingDarknessFish

Reputation: 14323

I don't think what you're asking for is possible in C, but you can sort of make it happen by abusing the comma operator. What follows is not code anyone should ever actually use and represents my stubborn attempts to fulfill the OP's original request beyond the bounds of reason.

#define CrWinDef(var,a,b,c,d,e,f,g,h,i,j,k,l)\
        (var=CreateWindowEx(a,b,c,d,e,f,g,h,i,j,k,l), \
        SendMessage(var, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)true), \
        var)

This macro takes as its first argument the name of the HWND variable being assigned to. Usage example is as follows:

HWND hwnd = CrWinDef(hwnd, ... ); //arguments a through l

Which expands to:

HWND hwnd = (hwnd = CreateWindowEx(a,b,c,d,e,f,g,h,i,j,k,l),
                    SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)true), 
                    hwnd);

Note that this won't work if you don't want to assign the result to a value, so you'd really have to have two macros: CrWinDef and CrWinDefRet or something like that.

Please just use a regular function.

Upvotes: 3

If compiling with GCC (or some compatible compiler, like Clang/LLVM) you could use its statement expr language extension and code:

#define CrWinDef(a,b,c,d,e,f,g,h,i,j,k,l) ({\
 HWND thw=CreateWindowEx(a,b,c,d,e,f,g,h,i,j,k,l);\
 SendMessage(thw, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), \
            (LPARAM)true);\
 thw; })

then later use: HWND hwnd = CrWinDef(...); but this won't work with e.g. Microsoft compilers.

As other suggested, a static inline function would be cleaner and more portable. Macros are brittle, e.g. if their argument is a i++, because it might be substituted several times, e.g. with

#define SQUARE(X) ((X)*(X))

used with SQUARE(i++) -this is undefined behavior and might increment i twice.

Upvotes: 2

vgru
vgru

Reputation: 51282

As other answers.have pointed out, macros cannot have return values.

But in most cases, a static inline function will produce the same result (function will be inlined), but with added type safety, which you don't get with macros.

Upvotes: 1

Austin Brunkhorst
Austin Brunkhorst

Reputation: 21130

#define blindly copy and pastes the definition wherever you reference it.

HWND hwnd = CrWinDef(...);

During the pre-processing step of compilation, the macro will expand to this

HWND hwnd = 
{
    HWND thw = CreateWindowEx(...);

    SendMessage(thw, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)true);

    return thw;
}

This doesn't entirely make sense as you're "assigning the value of a new scope" to a HWND.

You can modify your macro to also define the HWND instance in the current scope instead of looking at it from the perspective of a function where you take the return value.

#define CrWinDef(name, a,b,c,d,e,f,g,h,i,j,k,l)\
    HWND name = CreateWindowEx(a,b,c,d,e,f,g,h,i,j,k,l);\
    SendMessage(name, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)true);\

// "hwnd" now contains the HWND instance
CrWinDef(hwnd, ...);

Your last option is to just create an actual function that does what you're doing in the macro, but you would need to include the respective type information in the arguments.

Upvotes: 4

Andrew
Andrew

Reputation: 986

Your CrWinDef "function" doesn't have defined return type.

Why don't you use function?

Upvotes: 1

Related Questions