What are C macros useful for?

前端 未结 18 2043
-上瘾入骨i
-上瘾入骨i 2020-11-28 19:45

I have written a little bit of C, and I can read it well enough to get a general idea of what it is doing, but every time I have encountered a macro it has thrown me complet

18条回答
  •  执笔经年
    2020-11-28 20:06

    This excerpt pretty much sums up my view on the matter, by comparing several ways that C macros are used, and how to implement them in D.

    copied from DigitalMars.com

    Back when C was invented, compiler technology was primitive. Installing a text macro preprocessor onto the front end was a straightforward and easy way to add many powerful features. The increasing size & complexity of programs have illustrated that these features come with many inherent problems. D doesn't have a preprocessor; but D provides a more scalable means to solve the same problems.

    Macros

    Preprocessor macros add powerful features and flexibility to C. But they have a downside:

    • Macros have no concept of scope; they are valid from the point of definition to the end of the source. They cut a swath across .h files, nested code, etc. When #include'ing tens of thousands of lines of macro definitions, it becomes problematical to avoid inadvertent macro expansions.
    • Macros are unknown to the debugger. Trying to debug a program with symbolic data is undermined by the debugger only knowing about macro expansions, not the macros themselves.
    • Macros make it impossible to tokenize source code, as an earlier macro change can arbitrarily redo tokens.
    • The purely textual basis of macros leads to arbitrary and inconsistent usage, making code using macros error prone. (Some attempt to resolve this was introduced with templates in C++.)
    • Macros are still used to make up for deficits in the language's expressive capability, such as for "wrappers" around header files.

    Here's an enumeration of the common uses for macros, and the corresponding feature in D:

    1. Defining literal constants:

      • The C Preprocessor Way

        #define VALUE 5
        
      • The D Way

        const int VALUE = 5;
        
    2. Creating a list of values or flags:

      • The C Preprocessor Way

        int flags:
        #define FLAG_X  0x1
        #define FLAG_Y  0x2
        #define FLAG_Z  0x4
        ...
        flags |= FLAG_X;
        
      • The D Way

        enum FLAGS { X = 0x1, Y = 0x2, Z = 0x4 };
        FLAGS flags;
        ...
        flags |= FLAGS.X;
        
    3. Setting function calling conventions:

      • The C Preprocessor Way

        #ifndef _CRTAPI1
        #define _CRTAPI1 __cdecl
        #endif
        #ifndef _CRTAPI2
        #define _CRTAPI2 __cdecl
        #endif
        
        int _CRTAPI2 func();
        
      • The D Way

        Calling conventions can be specified in blocks, so there's no need to change it for every function:

        extern (Windows)
        {
            int onefunc();
            int anotherfunc();
        }
        
    4. Simple generic programming:

      • The C Preprocessor Way

        Selecting which function to use based on text substitution:

        #ifdef UNICODE
        int getValueW(wchar_t *p);
        #define getValue getValueW
        #else
        int getValueA(char *p);
        #define getValue getValueA
        #endif
        
      • The D Way

        D enables declarations of symbols that are aliases of other symbols:

        version (UNICODE)
        {
            int getValueW(wchar[] p);
            alias getValueW getValue;
        }
        else
        {
            int getValueA(char[] p);
            alias getValueA getValue;
        }
        

    There are more examples on the DigitalMars website.

提交回复
热议问题