Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > OK to disguise a macro function as a function?

Reply
Thread Tools

OK to disguise a macro function as a function?

 
 
Tomás Ó hÉilidhe
Guest
Posts: n/a
 
      02-12-2008

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
 
Reply With Quote
 
 
 
 
user923005
Guest
Posts: n/a
 
      02-13-2008
On Feb 12, 3:13*pm, "Tomás Ó hÉilidhe" <(E-Mail Removed)> 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.
 
Reply With Quote
 
 
 
 
Peter Nilsson
Guest
Posts: n/a
 
      02-13-2008
"Tomás Ó hÉilidhe" <(E-Mail Removed)> 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
 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      02-13-2008
On Feb 12, 3:13*pm, "Tomás Ó hÉilidhe" <(E-Mail Removed)> 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.
 
Reply With Quote
 
Army1987
Guest
Posts: n/a
 
      02-13-2008
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")
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Checking whether a string is a number in disguise? Peter Bunyan Ruby 9 11-23-2007 04:00 AM
How do you Disguise a Username? Denny B Computer Support 12 05-06-2006 02:04 AM
Disguise URL of downloadable file JJ ASP General 3 08-23-2004 01:11 PM
Disguise my email address Cal Smith Firefox 12 08-12-2004 09:49 PM
Can you disguise a website address ? NZed NZ Computing 9 08-07-2004 08:47 AM



Advertisments