0

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(...);
Dan
  • 221
  • 1
  • 4
  • 12
  • 4
    Macros aren't functions; they're preprocessor instructions. Try subst the macro text *verbatim* in the location where it occurs in your usage. Did you *really* want a `return` there? – WhozCraig Aug 22 '15 at 07:35
  • 3
    Is there a reason `CrWinDef` can't be a function? – ApproachingDarknessFish Aug 22 '15 at 07:39
  • Yes, I want to return that HWND. I know generally functions are used for returning a value, but I was really to lazy to write all data types. I did that now, but still I'm interestedto learn if something like this is possible. – Dan Aug 22 '15 at 07:40
  • why don't just use inline? – phuclv Aug 22 '15 at 07:48
  • 1
    Except that you're probably on Windows, you could arrange for the macro to become an `inline` function. Unfortunately, though, Microsoft doesn't support the old standard (C99); it only supports the quarter-century old standard (C89/C90). – Jonathan Leffler Aug 22 '15 at 07:53
  • 1
    I can recommend you my post here!!: [Faking functions with macros](http://stackoverflow.com/questions/18424458/how-much-is-it-possible-to-create-fake-functions-with-macros-in-c) – pablo1977 Aug 22 '15 at 07:55

6 Answers6

4

#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.

Austin Brunkhorst
  • 20,704
  • 6
  • 47
  • 61
3

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.

ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
2

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.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

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

Why don't you use function?

Andrew
  • 958
  • 13
  • 25
1

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.

vgru
  • 49,838
  • 16
  • 120
  • 201
0

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