PROBLEM
I need a way to generate unique values using a preprocessor directive. The aim is that each time the macro is called, it will have a unique integral identifier. But it should retain it's value across files. Kind of like a preprocessor counter for the number of times a call is made to the function.
FURTHER INFO
The macro I am using is:
#define LOG_MSG(a) log_msg(?)
- 'a' is a string that the user wants to print.
- log_msg is a custom function used to print a message on the UART
- The '?' if the part I need help with.
This macro would be defined at a single place only. During the preprocessing stage, the '?' would be replaced by a unique identifier. We are doing this to reduce the overhead that comes with strings as this code will run on an embedded device. After the preprocessing the identifiers and the related strings would be extracted and a table would be created that would map them (this would be on the application side).
Since this will be used across multiple files, I wanted a way to generate a unique identifier (integral not string) for every use across the multiple files(an identifier for every unique string would be ideal but not necessary).
Any ideas?
Please do mention if there is any missing or incomplete information
Notes
__COUNTER__
was the first thing I tried, but it doesn't hold across files.
__FILE__
would give me a string which defeats the purpose.
Some people mentioned using unique file identifiers. But I don't want to statically allocate these. We are using CCS(it's built on Eclipse Kepler) to build this code. So I was thinking that we could add something to the build system to do what @embedded_guy mentioned. Anyone know how to that?
Thanks
While its abuse of pre processor directives, you can generate pseudo random numbers as mentioned here and concatenate with another macro like
__FILE__
or__LINE__
, to generate a unique string.__COUNTER__
is the easy but nonstandard way of doing this.The Boost Preprocessor library will also be useful. For example, the following "
myheader.h
" header file will output a unique label wherever it's included.Your unique id will be generated at the line wherever you
#include "myheader.h"
Why not give the
#line
preprocessor directive a try? You can give unique starting line numbers to each of your source files and then use__LINE__
for your unique identifier. You would have to be certain that you maintain enough lines between each file so that all of the numbers remain unique. Here is an example:file_identifiers.h
log.h
log.c
main.c
OUTPUT
I would suggest that your solution is unimplementable with the standard C preprocessor, and a different solution is required. Also the proposed solution is incomplete - generating a UID alone is insufficient, you need to be able to associate that UID with the original string, and it is not clear how that is to be achieved.
It seems it would be simpler to write a separate custom preprocessor that searches the source for instances of
LOG_MSG( <some_string> )
, extracts<some string>
and replaces it with a UID generated by your preprocessor, and builds a string table for use by the host.The macro definition would then be:
But while in the original un-preprocessed code
a
will be a literal string, log_msg() will be definedlog_msg( int a )
.Execution of your preprocessor will then be a necessary pre-build step before compilation proper. Most IDEs support pre-build and pre-compile steps that can be used to integrate this tool, or adding as a make rule for example is simple enough.
Any attempt to compile un-preprocessed code will fail to compile because the parameter would be a string literal rather than an integer, so there is no danger of omitting to perform the pre-processing.
The only thing you will need to ensure than is that you use the string-table on the host that is associated with the specific build of the target code - but you had that problem in any case.
Note that it will only work when
a
is a literal string - but that is the case with the originally proposed solution in any case. Your pre-processor could check that and issue an error is a literal string were not passed.In general, it's not possible to assure a unique identifier is always generated for each macro expansion.
You can semi-solve the problem by using the builtin
__LINE__
macro, assuming the macro is used at most once per line. However, since you need to use it across multiple files, you'll need to manually define another macro that is unique per file. For example, at the top of foo.c:Then, you can use macro concatenation on
FILE_NAME
and__LINE__
to generate a unique identifier.If just a string will suffice (instead of an actual variable), you can use the
__FILE__
macro as well, combined with the "stringized" version of__LINE__
like so:Again, this assumes at most one invocation per logical line.
Some compilers also support a
__COUNTER__
macro, which can be used in place of__LINE__
, which allows for multiple invocations per logical line (but again, you need to combine it with something else, since__COUNTER__
is not unique across multiple translation units (aka C files)).