Thread: union for return values

  1. #1
    Registered User
    Join Date
    May 2007
    Posts
    41

    union for return values

    The Windows API functions can have different return types (DWORD, HRESULT, BOOL ecc.). In my functions I have to call several Windows API functions, so I declare a variable for each return type. For example:

    Code:
    int func()
    {
        BOOL bRet = FALSE;
        DWORD dwRet = 0;
        HANDLE hRet = NULL;
        HRESULT hrRet = S_OK;
    
        /*
        call functions
        /*
    }
    So I was thinkin' about defining an union like this

    Code:
    union uWinReturn
    {
        DWORD dw;
        BOOL b;
        HRESULT hr;
        HANDLE h;
    }
    So to write my function like this:

    Code:
    int func()
    {
        uWinReturn ret;
    
        ret.b = //...
        ret.dw = //...
    }
    Do you think it's a good idea?

    Also I was wondering about declaring the ret union as a global variable, one for each thread, so that I don't have to declare it on top of every function...What do you think about that?

    Thanks a lot for Your answers!

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Is this just to save typing?
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    May 2007
    Posts
    41
    to save typing and increase readability

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Except if you assign to more than one member, it would overwrite the previous ones? And how's the receiver supposed to know which of the fields is meant?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  5. #5
    Registered User
    Join Date
    May 2007
    Posts
    41
    The first thing I do after having called a function is to check its return value. So I don't bother if the next function overwrites it.

    I know wich filed to use for every function because I know its return type...

  6. #6
    Technical Lead QuantumPete's Avatar
    Join Date
    Aug 2007
    Location
    London, UK
    Posts
    894
    Quote Originally Posted by ZeroMemory View Post
    The first thing I do after having called a function is to check its return value. So I don't bother if the next function overwrites it.

    I know wich filed to use for every function because I know its return type...
    You misunderstand. Declaring a union means that all the variables in that union occupy the same space. Thus, if you have:
    Code:
    union {
        int a;
        int b;
    } MyUnion;
    
    MyUnion.a = 1;
    MyUnion.b = 2;
    printf ("a=%d\n", MyUnion.a);
    You'll get 2! You want a struct, methinks, not a union.

    QuantumPete
    "No-one else has reported this problem, you're either crazy or a liar" - Dogbert Technical Support
    "Have you tried turning it off and on again?" - The IT Crowd

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Very bad.

    The compiler can realize that if you only use a variable for a few lines in the code, it needn't actually "keep" the variable around for more than that particular bit of time. A union will definitely destroy such a usage, because the compile will (rightly or wrongly) assume that the same value has some meaning later on in the code.

    Using global variables is also very bad, because the compiler will often assume that any function that it doesn't see the whole code of (which means ANY function outside of your current source file) will modify the global variable - so the compiler will store and reload the value into the global variable even if it's not necessary for a correctness of the current code. This will lead to inefficient code.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I think he has something like this in mind:

    Code:
    void foo()
    {
        union_of_every_known_type u;
        u.dword = STD_OUTPUT_HANDLE;
        u.handle = GetStdHandle(u.dword);
        u.bool = SetConsoleMode(u.handle, ENABLE_LINE_INPUT);
        if (!u.bool) {
            u.dword = GetLastError();
            /* etc. etc. */
    }
    In this particular case you could of course just write:
    Code:
    int foo()
    {
         if (!SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_LINE_INPUT)) {
            DWORD error = GetLastError();
            /* etc. */
    }
    Anyway, it looks unorthodix and not really generally usable strategy: it breaks down as soon you need two variables at the same time. There is also no good name for the union variable if it is used to represent anything, so should you need more than one the code will become quite messy/undescriptive. And how large are your functions on average, that it hurts so much declare a few variables?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Registered User
    Join Date
    May 2007
    Posts
    41
    Quote Originally Posted by QuantumPete View Post
    You misunderstand. Declaring a union means that all the variables in that union occupy the same space. Thus, if you have:
    Code:
    union {
        int a;
        int b;
    } MyUnion;
    
    MyUnion.a = 1;
    MyUnion.b = 2;
    printf ("a=%d\n", MyUnion.a);
    You'll get 2! You want a struct, methinks, not a union.

    QuantumPete
    I know that...in fact is what I want. In my coding style I always do

    Code:
    ret = func1();
    if (FAILED(ret))
    {
        //handle error
    }
    ret = func2();
    if (FAILED(ret))
    {
        //handle error
    }
    //ecc.
    after every check for (FAILED(ret)) I don't need the ret value anymore, in fact I overwrite it calling the next function...

    ok...it's better to keep the variable inside the stack.

    So...you say that it's a bad idea?

  10. #10
    Technical Lead QuantumPete's Avatar
    Join Date
    Aug 2007
    Location
    London, UK
    Posts
    894
    Quote Originally Posted by ZeroMemory View Post
    So...you say that it's a bad idea?
    Actually, re-reading what you wrote (apologies for the confusion) I think it's a great idea to have a union. You only need each return value once before you use it again for another function call return value. I would definitely keep it on the stack though.

    QuantumPete
    "No-one else has reported this problem, you're either crazy or a liar" - Dogbert Technical Support
    "Have you tried turning it off and on again?" - The IT Crowd

  11. #11
    Registered User
    Join Date
    May 2007
    Posts
    41
    Ok...Thanks a lot!

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by QuantumPete View Post
    Actually, re-reading what you wrote (apologies for the confusion) I think it's a great idea to have a union. You only need each return value once before you use it again for another function call return value. I would definitely keep it on the stack though.

    QuantumPete
    But unions can lead to more code in the compiler, because:
    1. the compiler doesn't realize that the variable has limited scope (because another variant of the same union is used later - and the compiler may not understand ALL consequences of that)
    2. the compiler needs to store the result in the union (again, for the above reasons), rather than just using a register.

    Also, in cases where the returned value is NOT a BOOL, it is often useful to "keep around", because it is used by some other function later one (particularly HANDLE is usually of use later on to undo whatever the creation of the handle did, e.g. close the file). If you do not need the returned value, you can always write
    Code:
    if (FAILED(func2())
    {
       ... 
    }
    and never store the return value at all - that's the simplest option.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Returning a union is useless, because the calling function cannot know which type the result will be. Unless you set another flag as to the type, via a pointer parameter of a global variable. But the situation where a the result of an operation is not a always one of a set of compatible types is rare.

    You can use a union to minimise the amount of stack space local variables use, but unless it's a recursive function, stack space isn't generally a limmiting resource. Also instead of using a union, you can often use curly bracket blocks to make variables go out of scope early, and therefore optionally be reused.
    Last edited by King Mir; 10-08-2008 at 09:13 AM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  14. #14
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by King Mir View Post
    You can use a union to minimise the amount of stack space local variables use, but unless it's a recursive function, stack space isn't generally a limmiting resource. Also instead of using a union, you can often use curly bracket blocks to make variables go out of scope early, and therefore optionally be reused.
    And the compiler can OFTEN do "life-time analyzis" of variables anyways, so it will be able to re-use the space even if you do not limit the scope - as long as you don't make it too complicated for the compiler [these types of analysis are often quite complex, so they use arbitrary limits to prevent the compile time from being "infinite"].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #15
    Registered User
    Join Date
    May 2007
    Posts
    41
    for King Mir: I don't use the union as the return type of my functions. Every function has its own return type. Then to call functions I use the union to store their return value, be it an int, a DWORD, a long ecc.

    matsp, I could write
    Code:
    if (FAILED(func()))
    {
    }
    but if en error would occur, I couldn't know wich one it would be

    Quote Originally Posted by matsp
    2. the compiler needs to store the result in the union (again, for the above reasons), rather than just using a register.
    is this true even if the union is a local variable (local in the function)?

    anyway I'm gonna keep on with the classic method...I'll just declare a variable for each return type. Thanks for your help!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 10-29-2006, 05:04 AM
  2. Need help with project
    By chrisa777 in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2006, 05:01 PM
  3. Replies: 11
    Last Post: 03-24-2006, 11:26 AM
  4. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  5. Sorting a Union
    By andy in forum C Programming
    Replies: 4
    Last Post: 11-21-2001, 10:12 AM