Thread: preprocessor help

  1. #1
    Registered User
    Join Date
    Jun 2008
    Posts
    4

    preprocessor help

    Hi,

    I´m trying to create a routine to validate my casting. What I want to do is if my structure size is right put some code, if the code should report an error.
    Does anyone knows how can I do this at compile time?
    Code:
    #define COMPILE_TIME_ASSERT(test, a) \
    #if (test == 1) \
     *(char*)&(a)\
    #else\
    "Structure size error!"\
    #endif
    
    #define  BYTE(a)    COMPILE_TIME_ASSERT(sizeof(a) == 1, a)
    
    int main
    {
        char a,b;
        b = BYTE(a);
        BYTE(a) = a+1;
        return a;
    }
    Bruno

  2. #2
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Try something like this in your #else construct:

    Code:
    #error "Structure size error!"\
    Edit: Well, that is just for spitting out the error message. I'm not sure about the rest of your stuff.
    Last edited by MacGyver; 06-16-2008 at 08:29 AM.

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    No, you can't. "sizeof()" is done later during the compile than the preprocessor, so you can't do that.

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

  4. #4
    Technical Lead QuantumPete's Avatar
    Join Date
    Aug 2007
    Location
    London, UK
    Posts
    894
    The Preprocessor is just a dumb search-and-replace tool. It doesn't evaluate the code in any way. f you need to validate a sizeof() you'll need to have the compiler do it for you.

    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

  5. #5
    Registered User
    Join Date
    Jun 2008
    Posts
    4
    So far, I think It is getting the sizeof correctly, the problem is if has any way to define my
    #define COMPILE_TIME_ASSERT(test, a) with a preprocessor #if.

    As the #if gives me an error, I also tryied use (test) ? *(char*)&(a) : "error"; despite it compiles okay, it add the whole code on the define and not just the *(char*)&(a) or "error"

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I don't think this sort of thing can be done in C, or at least not easily.
    However, it can be done easily in C++.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Quote Originally Posted by Elysia View Post
    I don't think this sort of thing can be done in C, or at least not easily.
    However, it can be done easily in C++.
    How would it be done in C++ (curious, curious, don't really use C++)

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Psuedo code, but...
    Something along the lines of:
    Code:
    int main()
    {
        char mychar;
        int myint;
        char* c = safe_cast<char>(mychar); // Compiles
        c = safe_cast<char>(myint); // Won't compile
    }
    
    template<typename NewType, typename OriginalType>
    NewType& safe_cast(Original& Data)
    {
        STATIC_ASSERT(sizeof(NewType) == sizeof(OriginalType));
        return (NewType)Data;
    }
    This is dependant on boost's STATIC_ASSERT (or what it's called; can't remember 100&#37 macro.
    There are more ways to do this, of course, but this is the easy way.

    I haven't checked if this will compile, so it may contain a few errors, but the theory is sound.

    And in you don't want to use boost, you can just the compiler to complain.
    Something like:
    Code:
    int main()
    {
        char mychar;
        int myint;
        char* c = safe_cast<char>(mychar); // Compiles
        c = safe_cast<char>(myint); // Won't compile
    }
    
    template<bool bFail>
    struct dummy { static const bool bFail; };
    
    template<>
    struct dummy<true> { static const bool bFail = 'a'; }; // Causes a compile error about conversion from char to bool on purpose
    
    template<>
    struct dummy<false> { static const bool bFail = false; };
    
    template<typename NewType, typename OriginalType>
    NewType& safe_cast(Original& Data)
    {
        dummy< sizeof(NewType) != sizeof(OriginalType) >::bFail;
        return (NewType)Data;
    }
    Last edited by Elysia; 06-16-2008 at 10:32 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User
    Join Date
    Jun 2008
    Posts
    1
    A workaround I've used before is something like:

    Code:
    #define COMPILE_ASSERT(_cond)   typedef char _Dummy[(_cond)]
    Then you'd use it like:

    Code:
    int main()
    {
         COMPILE_ASSERT(sizeof(char) == 1);
    }
    You'd have to check if your compiler supports the definition of zero-element arrays (I remember some Linux compilers did). In which case, you'd redefine the macro to:

    Code:
    #define COMPILE_ASSERT(_cond)   typedef char _Dummy[(_cond) - 1]
    Of course, you won't get a proper error message when the assertion fails, but eh.

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by brunogon View Post
    So far, I think It is getting the sizeof correctly, the problem is if has any way to define my
    #define COMPILE_TIME_ASSERT(test, a) with a preprocessor #if.

    As the #if gives me an error, I also tryied use (test) ? *(char*)&(a) : "error"; despite it compiles okay, it add the whole code on the define and not just the *(char*)&(a) or "error"
    You also can't put preprocessor commands in a macro (well, you can, but it doesn't do what you want). The preprocessor FIRST examines for #if, #include, #define. It then replaces the COMPILE_TIME_ASSERT() with whatever you define it as - so it will replace your macro with #if .... Then the compiler proper comes to work, and it says "Huh? What's this #if - I've never heard of that... "

    So, you have to use regular if-statements to make the compiler see what you want. If it's even a little bit clever, it will then optimize away your test all together unless it's failing, and if it fails, then it will produce ONLY the code to perform your error message.

    I presume Elysia is referring to the template meta-programming stuff you can do in C++, where templates ARE expanded at compile time when sizeof() and such is known to the compiler.

    --
    Mats

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

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by matsp View Post
    I presume Elysia is referring to the template meta-programming stuff you can do in C++, where templates ARE expanded at compile time when sizeof() and such is known to the compiler.
    Indeed. It's potent stuff.
    Last edited by Elysia; 06-16-2008 at 10:48 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Jun 2008
    Posts
    4
    Thanks everybody,

    Unfortunately I can&#180;t use C++ code, I was trying to do some decent cast validation, but I think it is not possible.
    Tks again for your help

  13. #13
    Registered User
    Join Date
    Jun 2008
    Posts
    4
    Anyway, If I try implement this during execution, and not at the preprocessor, would it be possible? Any ideas?

    I would need something that makes posbile to use it exactly as *(char*)&(a).
    I mean a = safe_cast(b), safe_cast(b) = a

    Cheers
    Last edited by brunogon; 06-16-2008 at 11:13 AM.

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It would be possible at runtime, yes. Perhaps you can use...
    if (sizeof(a) != sizeof(b)) abort();
    ...type of macro.
    It's runtime, but it's better than nothing.
    (C++ can do it compile time.)
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Tags for this Thread