0

I have this code

struct counter_info {
    atomic_t counter;
    char *name;
} __attribute__((packed));

extern struct counter_info __start_counters;
extern struct counter_info __stop_counters;

#define __DOSOMETHING(F)                                    \
do{                                                         \
    static struct counter_info __counter_info_##F           \
    __attribute((__section__("counters")))                  \
    __attribute((__used__)) = {                             \
        .name = #F,                                         \
    };                                                      \
    atomic_set(&__counter_info_##F.counter, 0);             \
                                                            \
}while(0)

I call this macro as this:

__DOSOMETHING(FOO)

And I'd like to access __counter_info_##F from this other code

#define __DOSOMETHINGELSE(F)                                \
do{                                                         \
    atomic_inc(&__counter_info_##F.counter);            \
}while(0)

with __DOSOMETHINGELSE(FOO)

but I get an undeclared error from the compiler. Why is that? Can it be done?

EDIT:

The exact error is error: ‘__counter_info_FOO’ undeclared (first use in this function) note: in expansion of macro ‘__DOSOMETHINGELSE’

alexandernst
  • 14,352
  • 22
  • 97
  • 197
  • What's the exact error message? – haylem Sep 04 '13 at 23:14
  • 1
    (and also: dear god, what are you trying to do?) – haylem Sep 04 '13 at 23:16
  • @haylem Check my edit :) I'm doing black magic! (https://github.com/alexandernst/procmon if you really want to see, but please don't tell me I'm doing it wrong and that there are already other tools that do the same thing. I'm doing it for fun) – alexandernst Sep 04 '13 at 23:17
  • @wildplasser What do you mean? They are like this in my code, right? – alexandernst Sep 04 '13 at 23:20
  • BTW: identifiers with single or double leading underscores are reserved for the language and the implementation. – wildplasser Sep 04 '13 at 23:21
  • @alexandernst: I'll never judge anyone's right to use their free time to reinvent the wheel, that's my favorite past-time. But usually it may help to figure out what's wrong. – haylem Sep 04 '13 at 23:22
  • @haylem Believe me, the shortest explanation will be too long even for an entire SO question :P – alexandernst Sep 04 '13 at 23:23
  • @alexandernst: funny, actually did a MSc thesis on forensics solution using a similar concept (intercepting all or a set of syscalls to record a computer's activity for a post-mortem recovery or play-by-play investigation). – haylem Sep 04 '13 at 23:24
  • @haylem Oh, I guess GMTA :) hehehe – alexandernst Sep 04 '13 at 23:24
  • if the macro is invoked from within a function, `static struct counter_info __counter_info_##F ` will have function scope. (you probably want file scope) – wildplasser Sep 04 '13 at 23:28
  • @alexandernst: Well I hope you have a greater mind than we did back then: we didn't push much further past the prototype for the thesis and then life caught on. If you're interested, can always send you a link, it was just in 2008/09 so it may give background that's not so outdated. Think we still have the code on googlecode as well. – haylem Sep 04 '13 at 23:29
  • @haylem Oh, that would be great! I'd like to see how did you aproached the problem! – alexandernst Sep 04 '13 at 23:30
  • @wildplasser You mean if I call ```__DOSOMETHINGELSE``` from a function it will work? – alexandernst Sep 04 '13 at 23:31
  • No, the other way around. The data wil be _defined_ (by macro `__DO_SOMETHING` ) either in file scope, or in function scope. (you didn't show where/how it was involked) The data can only be referred in the same block (either function or file) – wildplasser Sep 04 '13 at 23:32
  • @wildplasser Well, I define the data from a function scope, calling ```__DOSOMETHING(FOO)``` from function ```a``` and then try to access the data, calling ```__DOSOMETHINGELSE(FOO)``` from function ```b```. Is that correct? – alexandernst Sep 04 '13 at 23:36
  • @alexandernst: I e-mailed you with the details. Feel free to reuse as needed. – haylem Sep 04 '13 at 23:40
  • @wildplasser: if you have `do { static int x = 0; ... } while (0);`, the `x` defined in that block is not accessible from any other block in the same function by name (the code represented by `...` can access it, but nothing else can). That's a simplified form of what's produced by the `__DOSOMETHING(F)` macro. The variable simply isn't accessible by name from outside the block. You can do tricks with pointers, of course, if the variable is static, but that is not 'access by name'. – Jonathan Leffler Sep 05 '13 at 00:38
  • Block scope: even worse. (but my reasoning is still correct) – wildplasser Sep 05 '13 at 00:44
  • @JonathanLeffler But then again, I do removed both the ```do``` and the ```while(0);``` and I still can't access the var. Why is that? – alexandernst Sep 05 '13 at 07:30
  • @alexandernst If you've deleted the do and while but left the braces then they by themselves still define a block which limits the scope of the variable. Also if as you say above you use __DOSOMETHINGELSE(FOO) in function b and __DOSOMETHING(FOO) in function a then that's never going to work, because __counter_info_FOO will, at most, be scoped to function a. If you need to access the same variable at in multiple functions without passing it as an argument then it has to be declared at file scope. – Nigel Harper Sep 05 '13 at 10:56
  • Also editing the question to show a simple but complete example of how you're using the macros would probably get you better answers - describing things a bit at a time isn't terribly effective. – Nigel Harper Sep 05 '13 at 11:01

2 Answers2

4

You can't get at that struct from another piece of code because you have declared it inside a braced block. C scope rules prohibit access to code outside that block. That's true even if you get your macro to generate correct name: __counter_info_F instead of __counter_info_FOO.

This isn't a #define issue, by the way. By the time C sees the code, all macro processing is done and the compiler only sees the tokens produced by the preprocessor.

Find a way to get the job done without macros...and THEN figure out a macro representation to ease the coding.

One way would be to use macros that don't use the do loops to seal off those variables. The problem now is to generate unique names. Look carefully at those macros and you'll see that that's the problem that the one-time-loops were created to solve...duplicate names creating double definitions. If you unwrap the macro generated code, you'll have to solve the duplicate name problem in another way...probably by adding macro arguments.

One thing, for the record: You don't need a compound statement like do or for to contain a plain block. Just enclosing in braces is good enough. You can take off the "do" at the beginning and the "while (0);" at the end, and get the same effect.

Mike Housky
  • 3,959
  • 1
  • 17
  • 31
  • Ok, so I removed the do{ }while(0); , it was there just-in-case, and I still can't access it. What else am I missing? – alexandernst Sep 05 '13 at 00:00
  • They still have to be in the same block. C is C, no matter what happens in the preprocessor. Like I said, find a way to get it done in C first, then figure out how to "macro-ize" that. – Mike Housky Sep 05 '13 at 00:06
  • @MikeHousky There are reasons that it's idiomatic to wrap macros in a do ... while loop. In certain contexts the effect is very different from just having braces - see http://stackoverflow.com/questions/154136/do-while-and-if-else-statements-in-c-c-macros – Nigel Harper Sep 05 '13 at 00:16
  • But Mike's analysis is correct. Writing `do { ... } while (0)` means that any variables defined in that `...` are strictly local to that block and cannot be accessed by name from any other (non-nested) block in the same function, let alone from outside the function. If the variable is static, you could arrange for a pointer defined outside the block to point to the variable inside the block, and then you'd be able to use that pointer to access the variable, but that is not 'access by name'. – Jonathan Leffler Sep 05 '13 at 00:33
  • @Nigel Harper: Thanks for the link. I've never had a problem with that, but I see the use. – Mike Housky Sep 05 '13 at 01:02
0

If the struct is declared static within a function, its visibility will be limited to that function. Example (without macros):

struct hoppa {
        int i;
        };

void start(void)
{
static struct hoppa one = {1};
}

void use_it(void)
{
one.i = 2; //FAIL
}
wildplasser
  • 43,142
  • 8
  • 66
  • 109