Macro that allocates storage and "returns" value

  • Thread starter Asbjørn Sæbø
  • Start date
A

Asbjørn Sæbø

I am replacing a number of functions with macros. Some of these
functions "do something" and then return a variable. This behaviour I
have found that I can emulate using the comma operator:

#define MYMACRO (do_something(), file_scope_variable - get_a_value() )


Other functions need local storage (but do not return a value), and
can be emulated using a block (a compund statement) to provide a scope
for a variable:

#define OTHERMACRO(some_var) \
{ \
uint8_t k; \
get_some_value(&k); \
some_var += k; \
}


The problem I have run into is a to replace a function that does both
of these, i.e. it both needs to allocate local storage and returns a
value. This seems to be problematic. I think (as far as I have found
in the standard) that a statement (e.g. a compund statement) does not
have (yield) a value. An introducing a block into a comma operator
expression gives compilation errors.

The C FAQ lists a number of techniques, but none of those seem to do
what I want here.) Is there a way to write a macro that can replace
such a function, or am I correct in assuming that it is not possible?


Asbjørn Sæbø
 
M

Mark Bluemel

Asbjørn Sæbø said:
I am replacing a number of functions with macros.

Why?
(Confession - I'm allergic to macros, by and large, and avoid them
whenever possible).
Some of these
functions "do something" and then return a variable. This behaviour I
have found that I can emulate using the comma operator:

#define MYMACRO (do_something(), file_scope_variable - get_a_value() )
OK.

Other functions need local storage (but do not return a value), and
can be emulated using a block (a compund statement) to provide a scope
for a variable:

#define OTHERMACRO(some_var) \
{ \
uint8_t k; \
get_some_value(&k); \
some_var += k; \
}

It's usually recommended to use do { } while(0) or some
similar hackery, so you can add ";" - see q10.4 in
http://www.c-faq.com
The problem I have run into is a to replace a function that does both
of these, i.e. it both needs to allocate local storage and returns a
value. This seems to be problematic. I think (as far as I have found
in the standard) that a statement (e.g. a compund statement) does not
have (yield) a value. An introducing a block into a comma operator
expression gives compilation errors.

The C FAQ lists a number of techniques, but none of those seem to do
what I want here.) Is there a way to write a macro that can replace
such a function, or am I correct in assuming that it is not possible?

It's not (portably) possible. GCC has a mechanism which can do this -
http://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/Statement-Exprs.html#Statement-Exprs
- but it's non-standard.

Otherwise, inline functions (where available) are probably the way
forward.
 
P

pete

=?utf-8?b?QXNiasO4cm4gU8OmYsO4?= said:
I am replacing a number of functions with macros. Some of these
functions "do something" and then return a variable. This behaviour I
have found that I can emulate using the comma operator:

#define MYMACRO (do_something(), file_scope_variable - get_a_value() )

Other functions need local storage (but do not return a value), and
can be emulated using a block (a compund statement) to provide a scope
for a variable:

#define OTHERMACRO(some_var) \
{ \
uint8_t k; \
get_some_value(&k); \
some_var += k; \
}

The problem I have run into is a to replace a function that does both
of these, i.e. it both needs to allocate local storage and returns a
value. This seems to be problematic. I think (as far as I have found
in the standard) that a statement (e.g. a compund statement) does not
have (yield) a value. An introducing a block into a comma operator
expression gives compilation errors.

The C FAQ lists a number of techniques, but none of those seem to do
what I want here.) Is there a way to write a macro that can replace
such a function, or am I correct in assuming that it is not possible?

My philosophy is that when a macro starts reserving memory,
then it's doing the job that functions were intended for,
and it's probably better to use a function instead in that case.
 
B

Ben Pfaff

Asbjørn Sæbø said:
I am replacing a number of functions with macros. Some of these
functions "do something" and then return a variable. This behaviour I
have found that I can emulate using the comma operator:

#define MYMACRO (do_something(), file_scope_variable - get_a_value() )

Why are you replacing functions with macros? It sounds like
functions are more appropriate for this use case.
 
A

Asbjørn Sæbø

Ben Pfaff said:
Why are you replacing functions with macros? It sounds like
functions are more appropriate for this use case.

Indeed they are, except for the fact that I am working on an embedded
platform and having "multiple call" problems, with functions being
called both from main() and from interrupts. Replacing functions with
macros is one step towards one way of solving this.

Asbjørn
 
A

Asbjørn Sæbø

Mark Bluemel said:
Why?
(Confession - I'm allergic to macros, by and large, and avoid them
whenever possible).

"Whenever possible" is the key word here. As I said in another post,
I am working on a limited (there is no stack) embedded platform with
functions that are called both from main() and from interrupts.

[...]
The problem I have run into is a to replace a function that does both
of these, i.e. it both needs to allocate local storage and returns a
value. [...]
It's not (portably) possible. GCC has a mechanism which can do this -
http://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/Statement-Exprs.html#Statement-Exprs
- but it's non-standard.

Otherwise, inline functions (where available) are probably the way
forward.

Unfortunately, this is neither GCC nor do I have the possibility of
inlining.

Thanks for your answer, though. I'll just have to solve the problem
another way, then. But it is good to know that I can abandon this
trail.

Asbjørn
 
B

Ben Pfaff

Asbjørn Sæbø said:
Indeed they are, except for the fact that I am working on an embedded
platform and having "multiple call" problems, with functions being
called both from main() and from interrupts. Replacing functions with
macros is one step towards one way of solving this.

Why not compile two copies of them, then, giving each copy a
different name? You could use macro tricks to change the names,
so that you only had one copy of each function in the source
code.
 
F

Flash Gordon

Asbjørn Sæbø wrote, On 09/01/08 21:37:
Indeed they are, except for the fact that I am working on an embedded
platform and having "multiple call" problems, with functions being
called both from main() and from interrupts. Replacing functions with
macros is one step towards one way of solving this.

It is a truly horrible way of solving it in my opinion. Better ways
would include:
Making the functions safely re-entrant
Making the functions inline if your compiler supports this
If the ISRs do not need to be re-entrant, but each in a separate
source file and provide static copies of the non-re-entrant functions
for the ISRs.

Note that using macros instead of functions will not solve re-entrancy
problems if your ISRs need to be re-entrant (I've done re-entrant ISRs,
but I would not recommend them to everyone).
 
W

Walter Roberson

Asbjørn Sæbø wrote, On 09/01/08 21:37:
It is a truly horrible way of solving it in my opinion. Better ways
would include:
Making the functions safely re-entrant
Making the functions inline if your compiler supports this

As the poster mentioned in another part of this thread that his
embedded system has no stack, my *speculation* was that it does not
have "return addresses" for functions, and the compiler is doing
a static branch to the function and static return -- which would
only allow each function to be called once. (Which doesn't explain
how the standard library would work, but since it is an embedded
system at least the poster would not have I/O portion of the
standard library to be concerned with.)

If this speculation were correct, it would be consistant with
"local variables" being possible if the compiler in question
ended up allocating the "local variables" at (possibly overlapping)
fixed addresses.

The result would not be consistant with the C standards in that
it would not allow recursion, but that might not be a problem
in that application environment.

This kind of construct of "no stack" could be extended to handle
multiple calls to the same routine if instead of using static
return addresses, the compiler used the equivilent of the old
IBM 360 BALR (Branch and Link Register), in which the return address
was put into a specific register instead of being put onto a
"stack". Multiple call levels could be handled by storing the
old return address in the fixed-addressed (possibly overlapped)
local variables possibility mentioned above. On the other hand,
I cannot think right at the moment why this would present problems
with "multiple calls" or ISRs.
 
T

Thad Smith

Walter said:
As the poster mentioned in another part of this thread that his
embedded system has no stack, my *speculation* was that it does not
have "return addresses" for functions, and the compiler is doing
a static branch to the function and static return -- which would
only allow each function to be called once. (Which doesn't explain
how the standard library would work, but since it is an embedded
system at least the poster would not have I/O portion of the
standard library to be concerned with.)

Typically on small embedded processors, there is a small stack for return
addresses, but it is not feasible or possible to use for data storage.
Applications on some small processors are constrained by the maximum stack
size, affecting design strategy.
If this speculation were correct, it would be consistant with
"local variables" being possible if the compiler in question
ended up allocating the "local variables" at (possibly overlapping)
fixed addresses.

Yes, that is typical for these small systems. Some compilers will generate
reentrant code, as an option, with significant additional overhead, many
simply don't support recursive calls. Linkers determine how to overlap RAM
based on the calling tree. These systems needs hints when function
pointers are used.

The earlier suggestions of using multiple copies of a function is often the
best approach. On one system, I defined a function body in a single macro,
then instantiated it within two separate functions. Another approach is to
write a single copy of a static function and include it in multiple
source files. These approaches aren't elegant, but does the job.
 
F

Flash Gordon

Thad Smith wrote, On 10/01/08 05:33:
I saw this after I posted.
Typically on small embedded processors, there is a small stack for
return addresses, but it is not feasible or possible to use for data
storage. Applications on some small processors are constrained by the
maximum stack size, affecting design strategy.

Yes, in which case the design strategy should be looked at not simply
code hackery.

The earlier suggestions of using multiple copies of a function is often
the best approach. On one system, I defined a function body in a single
macro, then instantiated it within two separate functions. Another
approach is to write a single copy of a static function and include it
in multiple source files. These approaches aren't elegant, but does the
job.

Personally I would go for the static function in a header, with of
course suitable documentation. Or if the code is small enough and the
compiler is not good enough inlining the code myself.
 
M

Mark Bluemel

Nickolai said:
Nice technique, thanks!

But, can I just add ";" ?

I don't understand your question. The FAQ explains what the issue is
and why this technique is needed.

What are you trying to do?
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top