3

I have the following macros

#define REG_PWR_CTRL 0x2D  
#define REG_FIFO_CTL 0x38

#define VERBOSE(...) \
    if(verbose) \
            printf(__VA_ARGS__);

#define READ_REGISTER(i2c_dev_file, REGISTER, variable) \
{ \
    variable = i2c_smbus_read_byte_data(i2c_dev_file, REGISTER); \
}

#define WRITE_REGISTER_VERBOSE(i2c_dev_file, REGISTER, value) \
{ \
    short int var = 0; \
    i2c_smbus_write_byte_data(i2c_dev_file, REGISTER, value); \
    usleep(100); \
    READ_REGISTER(i2c_dev_file, REGISTER, var); \
    VERBOSE(#REGISTER "    :0x%02X\n", var); \
}

I would like the REGISTER field to not be expanded in the following line
VERBOSE(#REGISTER " :0x%02X\n", var); \

For example, When I write
WRITE_REGISTER_VERBOSE(i2c_dev_fd, REG_PWR_CTRL, 0x1A);
WRITE_REGISTER_VERBOSE(i2c_dev_fd, REG_FIFO_CTL, 0xC6);
I get the output
0x2D :0x1A
0x38 :0xC6
I would like to obtain
REG_PWR_CTRL :0x1A
REG_FIFO_CTL :0xC6

I came across a lot of posts that spoke about adding an extra level of indirection.
I tried the answer described here https://stackoverflow.com/a/2653351/1761555 ..although I believe that that answer is for a different problem altogether..

What I did was

#define STRINGIFY(label) (#label)

#define WRITE_REGISTER_VERBOSE(i2c_dev_file, REGISTER, value) \
{ \
    short int var = 0; \
    i2c_smbus_write_byte_data(i2c_dev_file, REGISTER, value); \
    usleep(100); \
    READ_REGISTER(i2c_dev_file, REGISTER, var); \
    VERBOSE("%s    :0x%02X\n", STRINGIFY(REGISTER), var); \
}

But this still gives me the same output as before

Is there any way to achieve this?

Community
  • 1
  • 1
Guru Prasad
  • 4,053
  • 2
  • 25
  • 43
  • Take a look at [C `#define` macro for debug printing](http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing/) for a discussion of why the `if (verbose)` test is not good as written and what to do about it. You'll be OK if the only context in which you use `VERBOSE` is the macro WRITE_REGISTER_VERBOSE; if it gets used elsewhere, you'd need to be careful as it could cause the program to be reinterpreted (though it would most likely just generate syntax errors, but it might not be obvious why!). – Jonathan Leffler Dec 29 '13 at 20:48

3 Answers3

4

You could make REG_PWR_CTRL and REG_FIFO_CTL a value of some enum, like

  enum registers_en {
     REG__NONE,
     REG_PWR_CTRL = 0x2d,
     REG_FIFO_CTL = 0x38,
  };

Then REG_PWR_CTRL becomes a real identifier of some enum value, and is not macro-expanded in something else (because an enum definition is not a macro definition, and is not handled by the cpp preprocessor).

So define such an enum, and preprocess your source code (e.g. with gcc -C -E yoursource.c > yoursource.i) then look (e.g. with less yoursource.i) inside the preprocessed file. All occurrences of REG_PWR_CTRL will still be there.

Be aware the the preprocessor is conceptually the first phase of a compiler: even in compilers like current GCC 4.8 where the preprocessor is not an external program but implemented thru a libcpp internal library, the compiler works by first preprocessing the source code and obtaining a stream of lexemes, and then occurrences of REG_PWR_CTRL stay as lexemes (not as literal constants 0x2d as when you #define REG_PWR_CTRL 0x2d ...).

You need to read more about the preprocessor cpp, and take the habit to look into the preprocessed form.

Another advantage of enum-s is that if you compile with debugging info (e.g. gcc -g) the debugging info hence the debugger gdb knows about enum.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • I'm sorry but I don't quite understand how this would help me do the reverse-mapping..so in this case, I will still be able to obtain the value of `0x2D` from `REG_PWR_CTRL` but I don't follow how this will help me print '`REG_PWR_CTRL`'.. Also, I haven't mentioned it, but I have a lot of registers defined..not just one. – Guru Prasad Dec 29 '13 at 06:48
  • As I edited, just try using an `enum` like I suggest and look inside the preprocessed form. – Basile Starynkevitch Dec 29 '13 at 06:55
  • Thanks! Your solution works like a charm! I'm just waiting to see if this is possible to implement using `#define` before I accept yours – Guru Prasad Dec 29 '13 at 07:40
  • Is it possible to implement this functionality using *functions* rather than *macros*? If so, could you provide a template? – Guru Prasad Dec 29 '13 at 15:08
4

I modified your code for simplicity:

#include <stdio.h>

#define REG_PWR_CTRL       (0x2D) 
#define GET_VAR_NAME(var)  (#var)
#define VERBOSE(...)       (printf(__VA_ARGS__))
#define ANOTHER_LAYER(arg) (                                                      \
                               VERBOSE("%s = %#X; %s = %#X\n",                    \
                                       GET_VAR_NAME(REG_PWR_CTRL), REG_PWR_CTRL,  \
                                       GET_VAR_NAME(arg), arg)                    \
                           )                                                      \

int main(void)
{
    int num = 5;

    VERBOSE("%s = %#X\n", GET_VAR_NAME(REG_PWR_CTRL), REG_PWR_CTRL);
    ANOTHER_LAYER(num);

    return 0;
}

Output:

REG_PWR_CTRL = 0X2D
REG_PWR_CTRL = 0X2D; num = 0X5
Fiddling Bits
  • 8,712
  • 3
  • 28
  • 46
  • This is so weird..your code works as a standalone..but when I do the same in my program, it doesn't work..The only (stupid) reasons that I can think of : This is happening because 1) The macros are defined in different header files 2) My makefile is compiling small pieces before assembling them together 3) Other header file inclusions is causing this Other than that, I see no difference between your code and mine.. Editing my original question to show my implementation of your approach – Guru Prasad Dec 29 '13 at 07:40
  • 2
    @user1761555: you need an intermediate macro like `GET_VAR_NAME`, which your question don't have. – Basile Starynkevitch Dec 29 '13 at 07:42
  • I have now edited my post to show the use of the intermediate macro..As I had posted originally, I did try the solution in the link I referenced..it was unsuccessful though – Guru Prasad Dec 29 '13 at 07:44
  • 2
    @user1761555 It doesn't matter where your macros are `#define`d, as long as they're `#define`d before they're used. If the macros weren't `#define`d before use, you'd get an error. – Fiddling Bits Dec 29 '13 at 07:55
  • Well, then for *some* reason, it just doesn't work. I tried looking at the preprocessed output, and the macros have already been substituted with their values. Thus, the input to my `STRINGIFY()` macro is already the hex values – Guru Prasad Dec 29 '13 at 07:57
  • 1
    @user1761555 I expanded my answer to include nesting a macro. I'm not getting the problem you're getting... – Fiddling Bits Dec 29 '13 at 08:02
1

Use macros for simple things.

This is because:

  • You have more readable code
  • Easier to debug as the debugger has symbols you help you
  • They are very difficult to debug.

So just use functions for complex stuff. Use macros for simple stuff

Ed Heal
  • 59,252
  • 17
  • 87
  • 127