After searching quite a bit in the Internet for a solution I decided to ask here if my solution is fine.
I'm trying to write a simple and modular C logging library intended to be simple to disable and specially helping PhD students and researchers to debug an algorithm reducing as much as possibile the impact of the logging system.
My problem is that I want make possible for the user of the library to disable the logging system at compile time producing an executable in which the cost of the logger is 0.
The C code would look like this:
...
logger_t * logger;
result = logger_init(logger);
if(result == -1) {...}
...
this will simply initialize the logger. Looking for an example code I have checked the assert.h header but that soulution results in a list of warnings in my case. In fact, if logger_init() is substituted by 0 using the macro this will result in the variable logger never used.
For this reason I've decided to use this approach:
int logger_init(logger_t *logger);
#ifndef NLOG /* NLOG not defined -> enable logging */
int logger_init(logger_t *logger) {
...
}
#else /* NLOG defined --> the logging system must be disabled */
#define logger_init(logger) (int)((logger = NULL) == NULL)
#endif /* NLOG */
this does not result in warnings and I also avoid the overhead of calling the function. In fact my first try was to do like this:
int logger_init(logger_t *logger) {
#ifndef NLOG /* NLOG not defined -> enable logging */
...
#endif
return 0;
}
keep calling the function even if I do not need it.
Do you think my solution could be considered a good solution? Is there a better solution?
Thanks a lot, guys!
Cheers,
Armando
The standard idiom for that, at least in the 90s, was:
#ifndef NLOG
void logger_init(logger_t *logger);
void logger_log(logger_t *logger, ...);
#else
#define logger_init (void)sizeof
#define logger_log (void)sizeof
#endif
Remember that sizeof operands are not evaluated, although they are syntax checked.
This trick works also with variadic functions, because the sizeof operator will see an expresion with several comma operators:
logger_log(log, 1, 2, 3);
Converts to:
(void)sizeof(log, 1, 2, 3);
Those commas are not separating parameters (sizeof is not a function but an operator), but they are comma operators.
Note that I changed the return value from int to void. No real need for that, but the sizeof return would be mostly meaningless.
Can't your disabled version simply be a constant:
#ifndef NLOG /* NLOG not defined -> enable logging */
int logger_init(logger_t *logger) {
...
}
#else /* NLOG defined --> the logging system must be disabled */
#define logger_init(logger) 0
#endif /* NLOG */
This way, you just have (after pre-compilation): result = 0; which shouldn't produce any warnings.
Related
Is there a way to add an identifier that the compiler would replace with multiple lines of code?
I read up on macros and inline functions but am getting no where.
I need to write an Interrupt Service Routine and not call any functions for speed.
Trouble is I have several cases where I need to use a function so currently I just repeat all several lines in many places.
for example:
void ISR()
{
int a = 1;
int b = 2;
int c = 3;
// do some stuff here ...
int a = 1;
int b = 2;
int c = 3;
// do more stuff here ...
int a = 1;
int b = 2;
int c = 3;
}
The function is many pages and I need the code to be more readable.
I basically agree with everyone else's reservations with regards to using macros for this. But, to answer your question, Multiline macros can be created with a backslash.
#define INIT_VARS \
int a = 1; \
int b = 2; \
int c = 3;
#define RESET_VARS \
a = 1; \
b = 2; \
c = 3;
void ISR()
{
INIT_VARS
// do some stuff here ...
RESET_VARS
// do more stuff here ...
RESET_VARS
}
You can use inline function that will be rather integrated into place where it is called in source instead of really being called (note that behavior of this depends on several things like compiler support and optimizations setup or using -fno-inline flag feature). GCC documentation on inline functions.
For completeness - other way would be defining // do some stuff here... as pre-processor macro which again gets inserted in place where called; this time by preprocessor - so no type safety, harder to debug and also to read. Usual good rule of thumb is to not write a macro for something that can be done with function.
You are correct - it is recommended that you not place function calls in an ISR. It's not that you cannot do it, but it can be a memory burden depending on the type of call. The primary reason is for timing. ISRs should be quick in and out. You shouldn't be doing a lot of extended work inside them.
That said, here's how you can actually use inline functions.
// In main.c
#include static_defs.h
//...
void ISR() {
inline_func();
// ...
inline_func();
}
// In static_defs.h
static inline void inline_func(void) __attribute__((always_inline));
// ... Further down in file
static inline void inline_func(void) {
// do stuff
}
The compiler will basically just paste the "do stuff" code into the ISR multiple times, but as I said before, if it's a complex function, it's probably not a good idea to do it multiple times in a single ISR, inlined or not. It might be better to set a flag of some sort and do it in your main loop so that other interrupts can do their job, too. Then, you can use a normal function to save program memory space. That depends on what you are really doing and when/why it needs done.
If you are actually setting variables and returning values, that's fine too, although, setting multiple variables would be done by passing/returning a structure or using a pointer to a structure that describes all of the relevant variables.
If you'd prefer to use macros (I wouldn't, because function-like macros should be avoided), here's an example of that:
#define RESET_VARS() do { \
a = 1; \
b = 2; \
c = 3; \
while (0)
//...
void ISR() {
uint8_t a=1, b=2, c=3;
RESET_VARS();
// ...
RESET_VARS();
}
Also, you said it was a hypothetical, but it's recommended to use the bit-width typedefs found in <stdint.h> (automatically included when you include <io.h> such as uint8_t rather than int. On an 8-bit MCU with AVR-GCC, an int is a 16-bit signed variable, which will require (at least) 2 clock cycles for every operation that would have taken one with an 8-bit variable.
I would like to compute something according to the version of a library (which I can't change the values) by using C language.
However, the version of the library, that I am using, is defined as string by using #defines like:
/* major version */
#define MAJOR_VERSION "2"
/* minor version */
#define MINOR_VERSION "2"
Then, my question is: how to do define the macro STR_TO_INT in order to convert the strings MINOR_VERSION and MAJOR_VERSION to integer?
#if ((STR_TO_INT(MAJOR_VERSION) == 2 && STR_TO_INT(MINOR_VERSION) >= 2) || (STR_TO_INT(MAJOR_VERSION > 2))
//I perform an action...
#else
//I perform a different action
#endif
I prefer to define it as macro since I am using a lot of function from this library. Please feel free to give me any idea.
Preprocess the official library header, libheader.h, to generate your more useful information without the quotes in a new header, libversion.h:
sed -n -e '/^#define \(M[AI][JN]OR\)_VERSION "\([0-9][0-9]*\)".*/ {
s//#define NUM_\1_VERSION \2/p
}' libheader.h >libversion.h
You might need to be more flexible about allowing spaces and tabs around the separate parts of #, define and the macro name. I also assume there are no comments in the definition (trailing comments are handled):
/* This starts in column 1 - unlike the next line */
# define /* No comment here */ MAJOR_VERSION /* Nor here */ "2"
Now you can include both libheader.h and libversion.h and compare the numeric versions with impunity (as long as you get the expressions correct):
#include "libheader.h"
#include "libversion.h"
#if ((NUM_MAJOR_VERSION == 2 && NUM_MINOR_VERSION >= 2) || NUM_MAJOR_VERSION > 2)
…perform the new action…
#else
…perform the old action…
#endif
Strictly, the sed script will also convert MIJOR_VERSION and MANOR_VERSION; however, they're unlikely to appear in the library header, and you can ignore the generated numeric versions with ease. There are ways to deal with that if you really think it is an actual rather than hypothetical problem.
More seriously, if the library has complicated controls on the version information, it could be that a single header can masquerade as different versions of the library — there could be multiple lines defining the major and minor versions. If that's the case, you have to work a lot harder.
#define MAJOR_VERSION 2 will work anywhere, as an int, as you have, 2, there is no need for string/ conversions. You can directly do:
if (MAJOR_VERSION == 2) { /* version 2 */ }
else { /* not version 2 */ }
I wrote a program in C that uses a number of different random number generators and one of them is ISAAC (available at http://burtleburtle.net/bob/rand/isaacafa.html). It works well but the problem is that in rand.h rand() is redefined as a macro. In my program I want to use the standard C rand() function as well. I tried changing the name of the macro to rand12() but I cannot see any other place in ISAAC that the macro is called so this doesn't work.
Could you offer some ideas how I can keep the standard rand() function and use ISAAC as well?
Given that the header rand.h contains:
#ifndef STANDARD
#include "standard.h"
#endif
#ifndef RAND
#define RAND
#define RANDSIZL (8)
#define RANDSIZ (1<<RANDSIZL)
/* context of random number generator */
struct randctx
{
ub4 randcnt;
ub4 randrsl[RANDSIZ];
ub4 randmem[RANDSIZ];
ub4 randa;
ub4 randb;
ub4 randc;
};
typedef struct randctx randctx;
/* If (flag==TRUE), then use the contents of randrsl[0..RANDSIZ-1] as the seed. */
void randinit(/*_ randctx *r, word flag _*/);
void isaac(/*_ randctx *r _*/);
/* Call rand(/o_ randctx *r _o/) to retrieve a single 32-bit random value */
#define rand(r) \
(!(r)->randcnt-- ? \
(isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \
(r)->randrsl[(r)->randcnt])
#endif /* RAND */
You are going to need to do some work to the code to be able to use it alongside rand() from <stdlib.h>. The interface to the ISAAC rand() is different from the interface to rand() from <stdlib.h> too.
Create yourself a new header, "isaac.h", which defines cover functions to handle the peculiarities of the ISAAC system.
Maybe, if you aren't going to be working in a threaded context
#ifndef ISAAC_H_INCLUDED
#define ISAAC_H_INCLUDED
extern void isaac_init(unsigned long seed);
extern int isaac_rand(void);
#endif
You then implement those functions in isaac.c such that they call down onto the functions defined in rand.h, and isaac_rand() contains an invocation of the rand() macro from rand.h (providing a context from somewhere, which is where the non-threaded part comes in). You can decide what to do with the seed, or whether to change the seeding mechanism.
You can then use the isaac_init() and isaac_rand() functions in your code, as well as the normal rand() and srand().
I'd also upgrade the code in rand.h to provide full prototypes for the functions in the package. The commented prototypes is a legacy from when it was first written, back in the mid-90s, when standard C compilers were not universally accessible. The earliest date in the header is 1996; that's just on the cusp of when standard C compilers became almost universally available.
I note that the comments in the header (removed above) say the code is in the public domain; that means it is 100% legitimate to make any modifications you need.
isaac.c
#include "isaac.h"
#include "rand.h"
static randctx control;
void isaac_init(unsigned long seed)
{
assert(seed != 0);
randinit(&control, FALSE);
}
int isaac_rand(void)
{
return rand(&control);
}
This implementation ignores the seed you give, mainly because the structure expects eight 32-bit numbers to seed the randrsl member of the context structure (the one I called control). You could do something like use the seed value 8 times in a row instead of completely ignoring it, or add some number to it each time, or whatever other more complex seeding technique. You should seriously look at using /dev/urandom as a source of the seed:
#define DEV_URANDOM "/dev/urandom"
int ur = open(DEV_URANDOM, O_RDONLY);
if (ur >= 0)
{
read(ur, control.randrsl, sizeof(control.randrsl));
close(ur);
}
You'd put this code into isaac_init() before the call to randinit(), and you'd change the FALSE to TRUE. You'd probably also lose the seed argument to the isaac_init() function.
This leaves you with a problem of tracking the random seed to gain reproducibility (which can be important when debugging). That's for you to resolve, though — there are multiple ways to do that. You might have two initialize functions: void isaac_init(void) and void isaac_rsl(unsigned int *rsl) which takes an array of 8 unsigned int (or ub4) values and uses that as the seed instead of the output of /dev/urandom. Or you could pass a null pointer to mean "use output from /dev/urandom" and a non-null pointer to mean "use the values I've provided". Etc.
I have found this code for compareAndSwap in a StackOverflow answer:
boolean CompareAndSwapPointer(volatile * void * ptr,
void * new_value,
void * old_value) {
#if defined(_MSC_VER)
if (InterlockedCompareExchange(ptr, new_value, old_value) == old_value) return false;
else return true;
#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
return __sync_bool_compare_and_swap(ptr, old_value, new_value);
#else
# error No implementation
#endif
}
Is this the most proper way of having portable fast code, (Except assembly inlining).
Also, one problem is that those specific builtin methods have different parameters and return values from one compiler to another, which may require some additional changes like the if then else in this example.
Also another problem would be the behavior of these builtin methods in the machine code level, do they behave exactly the same ? (e.g use the same assembly instructions)
Note: Another problem would be if there is many supported platforms not just (Windows and Linux) as in this example. The code might get very big.
I would use a Hardware Abstraction Layer, (HAL) that allows generic code to be common - and any portable source can be included and build for each platform.
In my opinion, this allows for better structured and more readable source.
To allow you to better understand this process I would suggest Google for finding examples and explanations.
Hopefully this brief answer helps.
[EDIT] I will attempt a simple example for Bionix, to show how to implement a HAL system...
Mr A wants his application to run on his 'Tianhe-2' and also his 'Amiga 500'. He has the cross compilers etc and will build both binaries on his PC. He want to read keys and print to the screen.
mrAMainApplication.c contains the following...
#include "hal.h"
// This gets called every time around the main loop ...
void mainProcessLoop( void )
{
unsigned char key = 0;
// scan key ...
key = hal_ReadKey();
if ( key != 0 )
{
hal_PrintChar( key );
}
}
He then creates a header file (Remember - this is an example, not working code! )...
He creates hal.h ...
#ifndef _HAL_H_
#define _HAL_H_
unsigned char hal_ReadKey( void );
unsigned char hal_PrintChar( unsigned char pKey );
#endif // _HAL_H_
Now Mr A needs two separate source files, one for his 'Tianhe-2' system and another for his Amiga 500...
hal_A500.c
void hal_ReadKey( void )
{
// Amiga related code for reading KEYBOARD
}
void hal_PrintChar( unsigned char pKey )
{
// Amiga related code for printing to a shell...
}
hal_Tianhe2_VERYFAST.c
void hal_ReadKey( void )
{
// Tianhe-2 related code for reading KEYBOARD
}
void hal_PrintChar( unsigned char pKey )
{
// Tianhe-2 related code for printing to a shell...
}
Mr A then - when building for the Amiga - builds mrAmainApplication.c and hal_A500.c
When building for the Tianhe-2 - he uses hal_Tianhe2_VERYFAST.c instead of hal_A500.c
Right - I've written this example with some humour, this is not ear-marked at anyone, just I feel it makes the example more interesting and hopefully aids in understanding.
Neil
In modern C, starting with C11, use _Atomic for the type qualification and atomic_compare_exchange_weak for the function.
The newer versions of gcc and clang are compliant to C11 and implement these operations in a portable way.
Take a look at ConcurrencyKit and possibly you can use higher level primitives which is probably what most of the time people really want. In contrast to HAL which somewhat OS specific, I believe CK works on Windows and with a number of non-gcc compilers.
But if you are just interested in how to implement "compare-and-swap" or atomic actions portably on a wide variety of C compilers, look and see how that code works. It is all open-source.
I suspect that the details can get messy and they are not something that in general will make for easy or interesting exposition here for the general public.
Is there a way to get the C/C++ preprocessor or a template or such to mangle/hash the __FILE__ and __LINE__ and perhaps some other external input like a build-number into a single short number that can be quoted in logs or error messages?
(The intention would be to be able to reverse it (to a list of candidates if its lossy) when needed when a customer quotes it in a bug report.)
You will have to use a function to perform the hashing and create a code from __LINE__ and __FILE__ as the C preprocessor is not able to do such complex tasks.
Anyway, you can take inspiration by this article to see if a different solution can be better suited to your situation.
Well... you could use something like:
((*(int*)__FILE__ && 0xFFFF0000) | version << 8 | __LINE__ )
It wouldn't be perfectly unique, but it might work for what you want. Could change those ORs to +, which might work better for some things.
Naturally, if you can actually create a hashcode, you'll probably want to do that.
I needed serial valuse in a project of mine and got them by making a template that specialized on __LINE__ and __FILE__ and resulted in an int as well as generating (as compile time output to stdout) a template specialization for it's inputs that resulted in the line number of that template. These were collected the first time through the compiler and then dumped into a code file and the program was compiled again. That time each location that the template was used got a different number.
(done in D so it might not be possible in C++)
template Serial(char[] file, int line)
{
prgams(msg,
"template Serial(char[] file : \"~file~"\", int line : "~line.stringof~")"
"{const int Serial = __LINE__;");
const int Serial = -1;
}
A simpler solution would be to keep a global static "error location" variable.
#ifdef DEBUG
#define trace_here(version) printf("[%d]%s:%d {%d}\n", version, __FILE__, __LINE__, errloc++);
#else
#define trace_here(version) printf("{%lu}\n", version<<16|errloc++);
#endif
Or without the printf.. Just increment the errloc everytime you cross a tracepoint. Then you can correlate the value to the line/number/version spit out by your debug builds pretty easily.
You'd need to include version or build number, because those error locations could change with any build.
Doesn't work well if you can't reproduce the code paths.
__FILE__ is a pointer into the constants segment of your program. If you output the difference between that and some other constant you should get a result that's independent of any relocation, etc:
extern const char g_DebugAnchor;
#define FILE_STR_OFFSET (__FILE__ - &g_DebugAnchor)
You can then report that, or combine it in some way with the line number, etc. The middle bits of FILE_STR_OFFSET are likely the most interesting.
Well, if you're displaying the message to the user yourself (as opposed to having a crash address or function be displayed by the system), there's nothing to keep you from displaying exactly what you want.
For example:
typedef union ErrorCode {
struct {
unsigned int file: 15;
unsigned int line: 12; /* Better than 5 bits, still not great
Thanks commenters!! */
unsigned int build: 5;
} bits;
unsigned int code;
} ErrorCode;
unsigned int buildErrorCodes(const char *file, int line, int build)
{
ErrorCode code;
code.bits.line=line & ((1<<12) - 1);
code.bits.build=build & ((1<< 5) - 1);
code.bits.file=some_hash_function(file) & ((1<<15) - 1);
return code.code;
}
You'd use that as
buildErrorCodes(__FILE__, __LINE__, BUILD_CODE)
and output it in hex. It wouldn't be very hard to decode...
(Edited -- the commenters are correct, I must have been nuts to specify 5 bits for the line number. Modulo 4096, however, lines with error messages aren't likely to collide. 5 bits for build is still fine - modulo 32 means that only 32 builds can be outstanding AND have the error still happen at the same line.)