OK to disguise a macro function as a function?

Discussion in 'C Programming' started by Tomás Ó hÉilidhe, Feb 12, 2008.

  1. I'm not a fan of ALL CAPS, but of course I use it for macro
    functions to warn the programmer to be picky about what arguments they
    pass (for fear of multi-evaluation).

    However, I wonder what people think about _not_ using all caps when
    the macro function doesn't have any parameters, or when the arguments
    won't be multi-evaluated? For instance, in my own code, instead of
    having:

    inline void RowPinHigh(unsigned const i) { PORTA |= 1u << i; }

    , I have the following:

    #define RowPinHigh(i) ((void)(PORTA |= 1u << (i)))

    Firstly, the argument will only be evaluted once, so there's no
    problems on that front. The only other problem I can see is the issue of
    being able to take the function's address; I already ran into this
    problem in my own code:

    void (*RowPinAssert)(unsigned) = (first_pass ? RowPinHigh :
    RowPinLow);

    Still though, this isn't really so much a problem in that it will
    introduce bugs -- you'll simply get a compile error saying RowPinHigh
    wasn't declared (or perhaps if your compiler is set to Ancient Mode, a
    linker error saying a function called RowPinHigh that returns int
    couldn't be found).

    Currently I'm using an embedded systems compiler for programming
    microcontrollers, and it's not exactly 100% ANSI-compliant so I've had
    to do a few things such as:
    1) Use macros fuctions instead of inline functions (this actually
    _does_ result in my code being smaller and actually fitting onto the
    chip's memory).
    2) Use global variables instead of local variables in some instances
    because there's no stack (another strategy to save memory). I haven't
    tried using recursive functions but my bet is they don't work because
    static memory is used instead of a stack.

    Also, the compiler is very particular about what it considers const.
    For instance, you _can_ do the following:

    void Func(void)
    {
    int const i = 7;
    }

    , but you _can't_ do this:

    void Func(int x)
    {
    int const i = x; /* Compile Error */
    }

    The reason it gives a compile error is because when it sees the word
    "const", it assumes it can store it in read-only memory, i.e. a part of
    memory in the chip that can't be written to while the program is
    running. Therefore, you can't use const in the example immediately
    above.
    However, given that I didn't want to pick up the habit of omitting
    const, I decided to do the following instead:

    #define immutable

    void Func(int x)
    {
    int immutable i = x;
    }

    , and from there I use "const" when something is trully read-only, and
    "immutable" when I just don't want to change it. Then if I migrate my
    code to another system, I can just do:

    #define immutable const

    And if even that's too disgusting for some programmers, I can always do
    a "Find and Replace in all files" to change immutable to const.

    But anyway... back to the topic at hand, what do you think about _not_
    using all caps when there's no parameters or when the parameters won't
    be multi-evaluated?

    --
    Tomás Ó hÉilidhe
     
    Tomás Ó hÉilidhe, Feb 12, 2008
    #1
    1. Advertising

  2. Tomás Ó hÉilidhe

    user923005 Guest

    On Feb 12, 3:13 pm, "Tomás Ó hÉilidhe" <> wrote:
    >     I'm not a fan of ALL CAPS, but of course I use it for macro
    > functions to warn the programmer to be picky about what arguments they
    > pass (for fear of multi-evaluation).
    >
    >     However, I wonder what people think about _not_ using all caps when
    > the macro function doesn't have any parameters, or when the arguments
    > won't be multi-evaluated? For instance, in my own code, instead of
    > having:
    >
    >     inline void RowPinHigh(unsigned const i) { PORTA |= 1u << i; }
    >
    > , I have the following:
    >
    >     #define RowPinHigh(i)    ((void)(PORTA |= 1u << (i)))
    >
    >     Firstly, the argument will only be evaluted once, so there's no
    > problems on that front. The only other problem I can see is the issue of
    > being able to take the function's address; I already ran into this
    > problem in my own code:
    >
    >     void (*RowPinAssert)(unsigned) = (first_pass ? RowPinHigh :
    > RowPinLow);
    >
    >     Still though, this isn't really so much a problem in that it will
    > introduce bugs -- you'll simply get a compile error saying RowPinHigh
    > wasn't declared (or perhaps if your compiler is set to Ancient Mode, a
    > linker error saying a function called RowPinHigh that returns int
    > couldn't be found).
    >
    >     Currently I'm using an embedded systems compiler for programming
    > microcontrollers, and it's not exactly 100% ANSI-compliant so I've had
    > to do a few things such as:
    >     1) Use macros fuctions instead of inline functions (this actually
    > _does_ result in my code being smaller and actually fitting onto the
    > chip's memory).
    >     2) Use global variables instead of local variables in some instances
    > because there's no stack (another strategy to save memory). I haven't
    > tried using recursive functions but my bet is they don't work because
    > static memory is used instead of a stack.
    >
    >     Also, the compiler is very particular about what it considers const.
    > For instance, you _can_ do the following:
    >
    >     void Func(void)
    >     {
    >         int const i = 7;
    >     }
    >
    > , but you _can't_ do this:
    >
    >     void Func(int x)
    >     {
    >         int const i = x;  /* Compile Error */
    >     }
    >
    >     The reason it gives a compile error is because when it sees the word
    > "const", it assumes it can store it in read-only memory, i.e. a part of
    > memory in the chip that can't be written to while the program is
    > running. Therefore, you can't use const in the example immediately
    > above.
    >     However, given that I didn't want to pick up the habit of omitting
    > const, I decided to do the following instead:
    >
    >     #define immutable
    >
    >     void Func(int x)
    >     {
    >         int immutable i = x;
    >     }
    >
    > , and from there I use "const" when something is trully read-only, and
    > "immutable" when I just don't want to change it. Then if I migrate my
    > code to another system, I can just do:
    >
    >     #define immutable const
    >
    > And if even that's too disgusting for some programmers, I can always do
    > a "Find and Replace in all files" to change immutable to const.
    >
    > But anyway... back to the topic at hand, what do you think about _not_
    > using all caps when there's no parameters or when the parameters won't
    > be multi-evaluated?


    The ALL-CAPS sdreaming nature of function like macros has two purposes
    that I can see.
    1. It lets you know that you have no type safety.
    2. It lets you know that horrible side-effects are possible because
    you have no function call sequence point.

    I don't like function macros, but if I have to use them (e.g. I would
    probably have to use them in your situation) then I would make them
    all caps.
     
    user923005, Feb 13, 2008
    #2
    1. Advertising

  3. "Tomás Ó hÉilidhe" <> wrote:
    >     I'm not a fan of ALL CAPS, but of course I use it for
    > macro functions to warn the programmer to be picky about
    > what arguments they pass (for fear of multi-evaluation).


    There are other schemes, though they are considerably
    less popular than all caps.

    >     However, I wonder what people think about _not_ using
    > all caps when the macro function doesn't have any
    > parameters, or when the arguments won't be multi-
    > evaluated? For instance, in my own code, instead of
    > having:
    >
    >     inline void RowPinHigh(unsigned const i)
    > { PORTA |= 1u << i; }
    >
    > , I have the following:
    >
    >     #define RowPinHigh(i)    ((void)(PORTA |= 1u << (i)))


    It's not at all uncommon to implement 'inline' with macros...

    #define RowPinHigh(i) \
    ((void)(PORTA |= 1u << (unsigned int)(i)))

    void (RowPinHigh)(unsigned const);

    [P.S. note the extra cast in the parameter.]

    The most common usage for many people is in <stdio.h>,
    though they may not realise it.

    <snip>
    >     ... given that I didn't want to pick up the habit
    > of omitting const, I decided to do the following instead:
    >
    >     #define immutable
    >
    >     void Func(int x)
    >     {
    >         int immutable i = x;
    >     }
    >
    > , and from there I use "const" when something is trully
    > read-only, and "immutable" when I just don't want to
    > change it. Then if I migrate my code to another system,
    > I can just do:
    >
    >     #define immutable const
    >
    > And if even that's too disgusting for some programmers,
    > I can always do a "Find and Replace in all files" to
    > change immutable to const.


    Or do...

    #ifdef SET_IMMUTABLE_TO_CONST
    #define immutable const
    #else
    #define immutable
    #endif

    That way the code never changes, the default behaviour is
    for your principle compiler, and you can set the macro
    based on a compiler command line (or other) option. Many
    compilers for hosted systems will let you predefine
    macros, e.g. gcc -DMACRO_NAME. [Actually, I can't think
    of any that don't, but there are probably some tucked
    away.]

    > But anyway... back to the topic at hand, what do you
    > think about _not_ using all caps when there's no
    > parameters or when the parameters won't be multi-
    > evaluated?


    It's a style issue. Like many style issues, the only
    real issue how consistently you apply your style. The
    biggest mistake you can make is to mix styles.

    --
    Peter
     
    Peter Nilsson, Feb 13, 2008
    #3
  4. Tomás Ó hÉilidhe

    Kaz Kylheku Guest

    On Feb 12, 3:13 pm, "Tomás Ó hÉilidhe" <> wrote:
    >     I'm not a fan of ALL CAPS, but of course I use it for macro
    > functions to warn the programmer to be picky about what arguments they
    > pass (for fear of multi-evaluation).


    Some years ago I developed a run-time detection for this situation. If
    you have a macro m(x) whose expansion evaluates x more than once, it
    can produce a warning if x looks like it might be an expression with
    side effects.

    To use it you'd just #include "sfx.h", add sfx.c to your program and
    then write your macro like this:

    #define m(x) (one_use(SFX_CHECK(x)), another_use(x))

    instead of just this:

    #define m(x) (one_use(x), another_use(x))

    SFX_CHECK does the rest. It prints diagnostics on stderr, but of
    course it can be hacked to do whatever you want: assert, etc. There
    are some hooks in the source code if thread or interrupt safety is
    required. There is a run-time penalty which can only be eliminated by
    separate builds.

    >     However, I wonder what people think about _not_ using all caps when
    > the macro function doesn't have any parameters, or when the arguments
    > won't be multi-evaluated?


    Standard practice. If I made a list_for_each macro, I would call it
    that, and not shout in all caps.

    ANSI C has standard macros that are in lower case.

    Maybe we should even drop the silly habit of all caps even for
    preprocessor based constants. There is no need for it. There is
    vanishingly little value in knowing that some FOO is a preprocessor
    constant as opposed to some other kind of constant.. There is
    sometimes value in knowing /that/ FOO is a constant, regardless of
    what kind.

    For instance, in my own code, instead of
    > having:
    >
    >     inline void RowPinHigh(unsigned const i) { PORTA |= 1u << i; }
    >
    > , I have the following:
    >
    >     #define RowPinHigh(i)    ((void)(PORTA |= 1u << (i)))
    >
    >     Firstly, the argument will only be evaluted once, so there's no
    > problems on that front. The only other problem I can see is the issue of
    > being able to take the function's address;


    That problem is solved by having both implementations. This is how
    getc and getchar are typically implemented.

    Note that a function-like macro is only recognized if followed by an
    opening parenthesis, so you can have this:

    int foo();
    #define foo() ... inline expansion ..

    The address-of operator works just fine: &foo takes the address of the
    function, without the need to #undef foo.
     
    Kaz Kylheku, Feb 13, 2008
    #4
  5. Tomás Ó hÉilidhe

    Army1987 Guest

    Tomás Ó hÉilidhe wrote:

    > I'm not a fan of ALL CAPS, but of course I use it for macro
    > functions to warn the programmer to be picky about what arguments they
    > pass (for fear of multi-evaluation).
    >
    > However, I wonder what people think about _not_ using all caps when
    > the macro function doesn't have any parameters, or when the arguments
    > won't be multi-evaluated? For instance, in my own code, instead of
    > having:
    >
    > inline void RowPinHigh(unsigned const i) { PORTA |= 1u << i; }
    >
    > , I have the following:
    >
    > #define RowPinHigh(i) ((void)(PORTA |= 1u << (i)))
    >
    > Firstly, the argument will only be evaluted once, so there's no
    > problems on that front. The only other problem I can see is the issue of
    > being able to take the function's address;

    You can do:
    #define RowPinHigh(i) ((void)(PORTA |= 1u << (i)))
    inline void (RowPinHigh)(unsigned i) { RowPinHigh(i); }

    (But, for the macro to *actually* have the semantics of the functions, you
    ought to cast i to unsigned.

    --
    Army1987 (Replace "NOSPAM" with "email")
     
    Army1987, Feb 13, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dead RAM
    Replies:
    20
    Views:
    1,132
    John Harrison
    Jul 14, 2004
  2. D Senthil Kumar

    macro name from macro?

    D Senthil Kumar, Sep 20, 2003, in forum: C Programming
    Replies:
    1
    Views:
    590
    Jack Klein
    Sep 21, 2003
  3. Patrick Kowalzick
    Replies:
    5
    Views:
    485
    Patrick Kowalzick
    Mar 14, 2006
  4. JJ

    Disguise URL of downloadable file

    JJ, Aug 23, 2004, in forum: ASP General
    Replies:
    3
    Views:
    225
    Stuart Palmer
    Aug 23, 2004
  5. Peter Bunyan
    Replies:
    9
    Views:
    143
    Lloyd Linklater
    Nov 23, 2007
Loading...

Share This Page