CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    Join Date
    Jun 2006
    Location
    M31
    Posts
    885

    Silly #define Question

    Hey, I feel silly for asking this, but, say if I do:
    Code:
    #define abcdefg 12345
    
    void Test(){cout<<abcdefg;}
    This will work on all standards conforming C++ compilers, right?

    I mean, is it safe to use #define to define something? Will this glorified search & replace work on all preprocessors?

    Thanks in advance,
    sorry for such a retarded question.

    Edit: Ah, I just remembered about NULL, is this a standard #define, or something that's Microsoft (and others) specific?

  2. #2
    Join Date
    Sep 2006
    Location
    Sunshine State
    Posts
    517

    Re: Silly #define Question

    Yes, this kind of basic #defines should work on all compilers.
    Not much more to say there.

    NULL is part of the C standard and included in the standard library.

    if you're not sure, include this in your project:

    Code:
    #ifndef NULL
    #define NULL 0x00000000
    #endif

    Hope that helps,
    Andy

  3. #3
    Join Date
    Feb 2005
    Location
    Normandy in France
    Posts
    4,590

    Re: Silly #define Question

    Quote Originally Posted by Plasmator
    This will work on all standards conforming C++ compilers, right?
    Yes, as namezero111111 said.
    Quote Originally Posted by Plasmator
    I mean, is it safe to use #define to define something? Will this glorified search & replace work on all preprocessors?
    It's standard and portable.
    Safe? The answer is different.
    It has all the name clashes risks of macros and it lacks scopes.

    In C++ there are alternatives which follow the rules of scoped identifiers:
    Code:
    // at namespace scope
    static const int abcdefg=12345; /* it has internal linkage */
    
    class X {
      static const int hello=42; // at class cope... It has external linkage, and thus, requires a definition in one and not more than one translation unit.
    };
    const int X::hello; // definition... Don't put it in a header. Put it in a single translation unit.
    Another alternative (working under C as well as under C++):
    Code:
    enum {abcdefg=42};
    "inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards.
    Club of lovers of the C++ typecasts cute syntax: Only recorded member.

    Out of memory happens! Handle it properly!
    Say no to g_new()!

  4. #4
    Join Date
    Feb 2005
    Location
    Normandy in France
    Posts
    4,590

    Re: Silly #define Question

    Quote Originally Posted by namezero111111
    if you're not sure, include this in your project:

    Code:
    #ifndef NULL
    #define NULL 0x00000000
    #endif

    Hope that helps,
    Andy
    Correction: If you are sure that your compiler don't support NULL, then, you can define it yourself. Otherwise, including any standard header after this definition has undefined behavior.

    This NULL macro is defined in <cstddef> or <stddef.h>
    "inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards.
    Club of lovers of the C++ typecasts cute syntax: Only recorded member.

    Out of memory happens! Handle it properly!
    Say no to g_new()!

  5. #5
    Join Date
    Dec 2004
    Location
    Poland
    Posts
    1,165

    Re: Silly #define Question

    Quote Originally Posted by Plasmator
    I mean, is it safe to use #define to define something? Will this glorified search & replace work on all preprocessors?
    It is NOT glorified. It is pesky, stupid, and nasty. At least at C++. It is NOT safe to #define anything, except some cases, like include guards.

    Cheers,
    Hob

    EDIT: oops, I missed that SuperKoko already did similar point. I am sorry for repeating that once more
    Last edited by Hobson; November 12th, 2006 at 05:28 AM.
    B+!
    'There is no cat' - A. Einstein

    Use &#91;code] [/code] tags!

    Did YOU share your photo with us at CG Members photo gallery ?

  6. #6
    Join Date
    Sep 2006
    Location
    Sunshine State
    Posts
    517

    Re: Silly #define Question

    if you're not sure, include this in your project:


    Code:

    #ifndef NULL
    #define NULL 0x00000000
    #endif


    Hope that helps,
    Andy
    Correction: If you are sure that your compiler don't support NULL, then, you can define it yourself. Otherwise, including any standard header after this definition has undefined behavior.

    This NULL macro is defined in <cstddef> or <stddef.h>
    I'm not sure what the difference between what you're saying and I was saying is now.
    You mean if the compiler for some reason #defines NULL as something else than the lowest memory address? I wouldn't know of any C/C++ compiler where NULL (if #defined) is not 0x0.

    Is that what you mean?

  7. #7
    Join Date
    Feb 2005
    Location
    Normandy in France
    Posts
    4,590

    Re: Silly #define Question

    You mean if the compiler for some reason #defines NULL as something else than the lowest memory address? I wouldn't know of any C/C++ compiler where NULL (if #defined) is not 0x0.
    Borland C++ 5.0 in large DOS memory model is a counter-example. It defines NULL as 0L
    And, in C mode, it's defined as ((void*)0)
    If you define NULL as 0x0 and then, include any standard header, the behavior is undefined.
    For example, if you compile in C mode and that a standard header contain a macro such as:
    Code:
    #define DO_SOMETHING function_without_prototype(NULL)
    The function_without_prototype will not be called correctly, and the program may crash when the function returns or before.

    Another behavior would be a compile time error because of redefinition of NULL.

    PS: In C++, although the 0 constant expression can be converted to a pointer, nothing says that null pointers have to be the lowest memory address. You seem to assume a flat memory model... But, in segmented memory models, "lowest" has no meaning. And, there are platforms where the representation of null pointers is not the all-bits-zero pattern.
    Last edited by SuperKoko; November 12th, 2006 at 11:26 AM.
    "inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards.
    Club of lovers of the C++ typecasts cute syntax: Only recorded member.

    Out of memory happens! Handle it properly!
    Say no to g_new()!

  8. #8
    Join Date
    Sep 2006
    Location
    Sunshine State
    Posts
    517

    Re: Silly #define Question

    I'm sorry, I was talking about a case where the compiler does not define NULL, not when NULL is already defined by the STL.

    In that case, of course, it is best practice to use the STL #define of NULL, and not your own.

  9. #9
    Join Date
    Nov 2002
    Location
    Foggy California
    Posts
    1,245

    Re: Silly #define Question

    Quote Originally Posted by Hobson
    It is NOT glorified. It is pesky, stupid, and nasty. At least at C++. It is NOT safe to #define anything, except some cases, like include guards.
    Hobson, I'm surprised to see this statement come from you. Macros are not typesafe -- that is true. And one should not use them when there are type-safe alternatives. However, they solve many, many other problems that have nothing to do with header guards. Here are a couple examples from a project I'm currently working on where I'm wrapping a C++ library for .NET. (Note: I've anonymized the code.)

    Code WITHOUT macros:
    Code:
    int Method1()
    {
        try
        {
            return object.Method1();
        }
        catch (std::exception& e)
        {
            throw DotNetLibException(e);
        }
    }
    
    void Method2(int arg1, double arg2 /* , etc... */)
    {
        try
        {
            object.Method2(arg1, arg2 /* , etc... */);
        }
        catch (std::exception& e)
        {
            throw DotNetLibException(e);
        }
    }
    
    property int PropertyA
    {
        int get()
        {
            try
            {
                return object.PropertyAGet();
            }
            catch (std::exception& e)
            {
                throw DotNetLibException(e);
            }
        }
        void set(int newValue)
        {
            try
            {
                object.PropertyASet(newValue);
            }
            catch (std::exception& e)
            {
                throw DotNetLibException(e);
            }
        }
    }
    
    property double PropertyB
    {
        double get()
        {
            try
            {
                return object.PropertyBGet();
            }
            catch (std::exception& e)
            {
                throw DotNetLibException(e);
            }
        }
        void set(double newValue)
        {
            try
            {
                object.PropertyBSet(newValue);
            }
            catch (std::exception& e)
            {
                throw DotNetLibException(e);
            }
        }
    }
    
    // etc...
    Code WITH macros:
    Code:
    int Method1()
    {
        try
        {
            return object.Method1();
        }
        RECAST_EXCEPTIONS
    }
    
    void Method2(int arg1, double arg2 /* , etc... */)
    {
        try
        {
            object.Method2(arg1, arg2 /* , etc... */);
        }
        RECAST_EXCEPTIONS
    }
    
    DEFINE_PROPERTY(PropertyA, int)
    DEFINE_PROPERTY(PropertyA, double)
    
    // etc...
    Macro definitions:
    Code:
    #define RECAST_EXCEPTIONS            \
        catch (std::exception& e)        \
        {                                \
            throw DotNetLibException(e); \
        }
    
    #define DEFINE_PROPERTY(NAME, TYPE)     \
    property TYPE NAME                      \
    {                                       \
        TYPE get()                          \
        {                                   \
            try                             \
            {                               \
                return object.NAME##Get();  \
            }                               \
            RECAST_EXCEPTIONS               \
        }                                   \
        void set(TYPE newValue)             \
        {                                   \
            try                             \
            {                               \
                object.NAME##Set(newValue); \
            }                               \
            RECAST_EXCEPTIONS               \
        }                                   \
    }
    The # and ## err... keywords (I know they aren't keywords -- I just forgot what they are called) prove to be very useful. There have been times when writing C# and VB.NET code that I really miss these types of macros.

    - Kevin
    Last edited by KevinHall; November 12th, 2006 at 11:37 PM.
    Kevin Hall

  10. #10
    Join Date
    Dec 2004
    Location
    Poland
    Posts
    1,165

    Re: Silly #define Question

    Quote Originally Posted by KevinHall
    Hobson, I'm surprised to see this statement come from you. Macros are not typesafe -- that is true. And one should not use them when there are type-safe alternatives. However, they solve many, many other problems that have nothing to do with header guards.
    Yay, dunno should feel proud or stupid... Anyway, with my not-very-long programming experience (as professionnal I mean, 14 months is not much I think) I faced some situations where macros gave me LOTS of pain. You could feel very surprised when third-party library used in your project changes calling convention of every function exported from your library... Digging through ~3MB source files generated with --save-temps is no fun. Most irritating thing is that even when YOU know how to use macros, there is always someone (co-worker, library author, etc) who will screw something. There are some guidelines about using macros, there is some personal preference. My preference is: 'PLEASE, NO'. As for your example: It makes things a bit easier, but I feel kinda strange when I read code and see try not paired with catch. 'How does this even compile?' I ask myself at first glance. And after a second I come to conclusions: 'Aaahh.. Preprocessor magick!'. Another thing is that this approach makes debugging difficult (at least at Visual Studio which I use the most). I noticed surprising relation among people around me, that guys who happily create multiline macros are guys who hardly ever use 'Step into' button... But thats just me. I am not pro and theres long way before me. Theres looong talk if macros are good or not, when they are, and whey they are not. I guess that discussion would not fit into CG quota.

    Best regards,
    Hob

    PS. Operators?
    B+!
    'There is no cat' - A. Einstein

    Use &#91;code] [/code] tags!

    Did YOU share your photo with us at CG Members photo gallery ?

  11. #11
    Join Date
    Feb 2005
    Location
    "The Capital"
    Posts
    5,306

    Re: Silly #define Question

    Quote Originally Posted by Hobson
    As for your example: It makes things a bit easier, but I feel kinda strange when I read code and see try not paired with catch.
    Have one for try part as well.. But yup.. you can't step into it.. debugging is difficult.. moreover, that wouldn't look very pretty had there been a need to add a few more handlers...

  12. #12
    Join Date
    Nov 2002
    Location
    Foggy California
    Posts
    1,245

    Re: Silly #define Question

    Quote Originally Posted by Hobson
    Anyway, with my not-very-long programming experience (as professionnal I mean, 14 months is not much I think)
    From what I've seen you write at CG, I'd have thought you've been programming longer professionally. (That's why I made the comment about being surprised.)

    Quote Originally Posted by Hobson
    As for your example: It makes things a bit easier, but I feel kinda strange when I read code and see try not paired with catch. 'How does this even compile?' I ask myself at first glance. And after a second I come to conclusions: 'Aaahh.. Preprocessor magick!'.
    Well, perhaps I should use a slightly more verbose name for the macro then. Something like CATCH_CAST_AND_RETHROW_EXCEPTIONS. (And as exterminator (jokingly I think) pointed out, I could have created a macro for 'try': TRY or the more verbose TRY_THIS_UNMANAGED_CODE, but I don't see the benefit there).

    Quote Originally Posted by Hobson
    Another thing is that this approach makes debugging difficult (at least at Visual Studio which I use the most). I noticed surprising relation among people around me, that guys who happily create multiline macros are guys who hardly ever use 'Step into' button...
    I hear you. People shouldn't be writing macros foor parts of code that need such inspection. My example shows the macros performing very simple actions. I first developed the code as non-macros, carefully debugged that code (which as you can see wasn't that difficult), and then created the macros from debugged code. Then I was able to quickly add new properties and methods. (The best thing was that without macros, I had about 5 times as many copy-and-paste errors than when I switched to macros because there were so many places that needed replacing.) Since the time I created the macros, I haven't had to step inside to see what was happening inside. I can "Step into" past the macros just fine and it hasn't produced a problem yet.

    But anyway, macros do have their problems, but they also when used carefully in the right situations do make some things simpler and more robust.

    And by the way, the situation the exterminator pointed out did occur on my project. There was a need to add another catch statement to every method and property in our wrapper -- which at that point included ~800 methods and properties. Because of the macros, the new catch statements only had to be added to a single place.

    - Kevin

    P.S. If you ever have to step into multi-line macros, you can always pre-process the files and use the processed files for stepping into. It's a bit of work, but it's a ton easier than mentally stepping through long multi-lined macros. (And I'm of the opinion that long multi-lined macros that have a high likelyhood of containing bugs should not be macros.)

    P.P.S. Exterminator, I just finally understood your name. You go kill bugs. I can't believe I never saw that before!
    Kevin Hall

  13. #13
    Join Date
    Nov 2002
    Location
    Foggy California
    Posts
    1,245

    Re: Silly #define Question

    Quote Originally Posted by Hobson
    PS. Operators?
    Yeah, preprocessor operators. Total brain-fart there.
    Kevin Hall

  14. #14
    Join Date
    Oct 2002
    Location
    Singapore
    Posts
    3,128

    Re: Silly #define Question

    Not to forget about writing code for different platform. As many have already known, winsock2 is not completely BSD compatible. If we need to write code that compiles and runs on Linux and Windows, we have no choice but to use macro.

    Code:
    #if define _WIN32
      #include <Winsock2.h>
      #include <ws2tcpip.h>
      #include <errno.h> 
      #include <stdio.h>
    
      // Using similar function but being named differently.
      #define snprintf _snprintf
      
      // Creating wrapper function for BSD compatible function.
      extern int inet_aton(const char *cp, struct in_addr *address);
    #else if define __GNUC__
      #include <sys/types.h>
      #include <sys/socket.h>
    #endif
    quoted from C++ Coding Standards:

    KISS (Keep It Simple Software):
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.

    Avoid magic number:
    Programming isn't magic, so don't incant it.

  15. #15
    Join Date
    Feb 2005
    Location
    "The Capital"
    Posts
    5,306

    Re: Silly #define Question

    Quote Originally Posted by KevinHall
    From what I've seen you write at CG, I'd have thought you've been programming longer professionally. (That's why I made the comment about being surprised.)
    Agree!
    Quote Originally Posted by KevinHall
    But anyway, macros do have their problems, but they also when used carefully in the right situations do make some things simpler and more robust.
    I am open to it..
    Quote Originally Posted by KevinHall
    And by the way, the situation the exterminator pointed out did occur on my project. There was a need to add another catch statement to every method and property in our wrapper -- which at that point included ~800 methods and properties. Because of the macros, the new catch statements only had to be added to a single place.
    So, you are saying you expected the same exception handler at all places apart from the std::exception one? This doesn't sound very good an means you would be having quite a lot of unneeded catch handlers. std::exception is okay because, all standard and your custom exceptions would derive from them. I have seen RogueWave exceptions not deriving from std::exception, if your case was something like that where you added another base exception handler for a library exception heirarchy - then probably it is fine but still there may be many routines where you might not be using that library members.
    Quote Originally Posted by KevinHall
    P.P.S. Exterminator, I just finally understood your name. You go kill bugs. I can't believe I never saw that before!
    Heh.. You got it right.. For more information about my avatar take a look here - http://abnegator.blogspot.com/2005/0...d-insects.html (from last year June)

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured