Having Compiling trouble with definition function in another header - c

So I was wondering why I am getting the following error:
Error 1 undefined reference to `MIN_COUNTER' C:\Users\Wyatt
Crosby\Dropbox\Atmel
Studio\ReflowController\ReflowController\ReflowController\Debug/.././ReflowController.c 146 1 ReflowController
When in PID.h I have:
#ifndef PID_H
#define PID_H
#define LCD_SCREEN_SIZE 16
#define MAX_COUNTS 180
#define OVEN_MAX_TEMP 260
#define OVEN_MIN_TEMP 0
#define MIN_COUNTER(x,a) tempLookupArray[x] < a ? x : MIN_COUNTER(x+1,a)
#define FIND_COUNTER(a) a <= OVEN_MIN_TEMP ? MAX_COUNTS : MIN_COUNTER(0,a)
const float tempLookupArray[MAX_COUNTS];
...
Where tempLookupArray is define further in PID.c:
const float tempLookupArray[MAX_COUNTS] = {
260.00,
260.00,
260.00,
259.99,
259.98,
259.96,
...
And in ReflowController.c I include PID.h and write:
TriggerCounter = FIND_COUNTER(PIDgain);
Where PIDgain is local and of type 'float', and TriggerCounter is global and of type 'volatile int'
It seems to be the fact that I am trying to call MIN_COUNTER from inside MIN_COUNTER and doesn't have any sort of prototype for it yet (if it were a function) . . .
Any thoughts from you smart guys out there?
Thanks!

After the preprocessor has gone through your code,
TriggerCounter = FIND_COUNTER(PIDgain);
becomes
TriggerCounter = PIDgain <= 0 ? 180 : tempLookupArray[0] < PIDgain ? 0 : MIN_COUNTER(0+1,PIDgain);
At that point, the preprocessor hands the code to the compiler and linker who look for a method called MIN_COUNTER but can't find one. The preprocessor doesn't work recursively in a case like that. Imagine if it did: The code you wrote would send the compiler in an infinite loop; it would need to expand MIN_COUNTER and to do that, it needs to expand another MIN_COUNTER and so on...
Try using actual functions instead of macros
int min_counter(int x, float a) {
return tempLookupArray[x] < a ? x : min_counter(x+1,a);
}
int find_counter(float a) {
return a <= OVEN_MIN_TEMP ? MAX_COUNTS : min_counter(0,a);
}
In addition to recursing properly, it will also avoid some of the caveats of macros (For example, FIND_COUNTER(i++) would increment i multiple times, whereas find_counter(i++) wouldn't)

Related

Array of macros in c -- is it possible

I was wondering if it is possible to create something like an array of macros.
I've implemented the following code which works:
struct led_cmds_
{
ioport_pin_t *commands[LED_COUNT] ;
};
struct led_cmds_ the_led_cmd_ ;
void populate() {
the_led_cmd_.commands[0] = SPECIFICPIN(0);
}
and in main:
int main(void)
{
//.....
populate();
LED_On(the_led_cmd_.commands[0]);
}
SPECIFICPIN(x) is macro defined as:
#define SPECIFICPIN(X) (LED##X##_PIN)
What I was hoping for is a way to is a way to do something like this:
#define ioport_pin_t* ARR_LED[LED_COUNT] \
for (int j = 0; j < LED_COUNT; j++) ARR_LED[j] = SPECIFICPIN(j);
and then only need to call the following when I want to use the specific pin
LED_On(ARR_LED[some_number])
when I try to do that I get an ARR_LED undeclared (first use in this function) error.
When I try to call SPECIFICPIN(x) where x is an int iterator in a for loop for example, I get an error saying something like 'LEDx_PIN' undeclared...
You need to work on your terminology. An array of macros is not possible. Macros are no data type, but rather pure text replacement before your program is actually compiled.
I guess " populate an array using macros " is what you want to do. But it is not possible to do that in a compile-time loop - What you seem to want to achieve with your ioport_pin_t macro attempt. Macros do not have the capability to expand to more instances of text elements than you have initially given. There is no such feature as looping at compile time through macro expansions and do repetitive expansion of macros.
Your for loop loops at run-time, while the macro is being expanded at compile-time. Once you have made yourself aware what is done by the preprocessor what is done by the compiler, and what is done at run-time by the finished program, you will see that will not work.
Something like
#define P(X) {(LED##X##_PIN)}
ioport_pin_t *commands[LED_COUNT] = {
P(0), P(1), P(2),......}
#undefine P
Would be the closest thing possible to what you seem to want. Note the main use of the pre-processor is not to save you typing effort - You would be better off using copy & paste in your editor, achieve the same thing and have clearer code.
An array as tofro's answer is the way to go. However in cases that couldn't be solved simply with an array then there's another way with switch
#define SPECIFICPIN(X) (LED##X##_PIN)
void setpin(int pin, int value)
{
switch (pin)
{
case 1:
SPECIFICPIN(1) = value;
doSomething(); // if needed
break;
case x: ...
default: ...
}
}

goto label trick in a macro for condition

There was one evil macro trick I DON'T REMEMBER and it was a lot like this:
public :
var = 3;
}
Which should expand to
if(route == ROOTING_PUBLIC)
{
var = 3;
}
How can I achieve something like this ?
Macros are used to reduce clutter; though a lot of clutter indicates problems with the program structure.
The OP's notion of the possible macro does not match C-syntax. But something along those lines might be:
#define if_ROOTED(name) if (ROOTED_##name & input) { output = e##name; }
#define ROOTED_FIRST 16
#define ROOTED_SECOND 64
#define eFIRST 1
#define eSECOND 2
if_ROOTED(FIRST);
if_ROOTED(SECOND);
where input and output and the repetitive test are the "clutter" to be eliminated. Making a table would be a better way to reduce clutter; however OP asked for a hint about macros.
Now that I found the implementation of such bad idea, I also could understand the deeper sense in it.
The code
#define public if(route == ROOTING_PUBLIC) { public_offset
The usage
public :
var = 3;
} // <-- makes no sense
The idea
To avoid loops, to reduce the spaghetti code and to demonstrate more exotic code. It will be better to be implemented with an id system as such:
#define public(id) if(route == ROOTING_PUBLIC) { public_##id
And then if the user decides to loop the code (that by semantics will be invoked solely "publicly"):
public(2) :
var = 3;
if(var > 3) goto public_2; // or #define repeat(x, id) goto x##_##id
}
Even better version of it will include the omitting of magic numbers, replacing it with user_id

Passing values to macros by for loop

I want to pass values to the macro through for loop,but when i try to pass values it gives error, please help m as fast as possible. When values of i are passed to macro as Valve(i) it gives error
my code given below:
#define Valve(x) stTest.bValve##x##_Cmd
typedef struct OperationFlags
{
int bValve1_Cmd;
int bValve2_Cmd;
}FLAGS_TypeDef;
void main(void)
{
FLAGS_TypeDef stTest;
int j,i;
stTest.bValve1_Cmd = 4;
stTest.bValve2_Cmd = 9;
for(i=1;i<=2;i++)
{
j=Valve(1);
printf("%d",j);
}
}
It is normal!
The preprocessor (the "thing" that processes the macros) is run BEFORE the C compiler. So, it is only valid when it produces compilable code.
In your case, if you use the code you show
j=Valve(1)
it will work for that value, since it will produce:
j=stTest.bValve1_Cmd
but it will do the entire loop only with that value.
When you change the parameter "1" with the "i" for actually doing the loop, then it will produce:
j=stTest.bValvei_Cmd
which is invalid.
To do what you want, just use a vector:
typedef struct OperationFlags
{
int bValve_Cmd[2];
}FLAGS_TypeDef;
#define Valve(x) stTest.bValve_Cmd[x]
//....
for(i=1;i<=2;i++)
{
j=Valve(1);
printf("%d",j);
}
Macro replacement is done well before runtime, so you cannot use a variable X containing the value 2 to get stTest.bValve2_Cmd. Instead, you will get stTest.bValveX_Cmd, for which no symbol exists.
You will have to find another way of doing this, such as having an array of values for which you can use X to select:
#define Valve(x) stTest.bValveX_Cmd[x]
typedef struct OperationFlags {
int bValveX_Cmd[2];
} FLAGS_TypeDef;
try this #define Valve(x) (x == 1 ? stTest.bValve1_Cmd : stTest.bValve2_Cmd)
#define Valve(x) (*(&stTest.bValve1_Cmd + (x-1)))
note : It may not work if the environment changes. Also it can not be used in the bit field.
add check
#define Valve(x) (*(&stTest.bValve1_Cmd + (x-1))); \
assert(offsetof(FLAGS_TypeDef, bValve2_Cmd) == sizeof(int))

Function macro argument to function macro

I have some macros to define bit fields in registers easily (I use these for read, modify, write operations, set, gets etc). I'm getting a compiler error that I don't understand.
// used just for named arguments -- to make the values more clear when defined
#define FLDARGS(dwOffset, bitStart, bitLen) dwOffset, bitStart, bitLen
// extract just the dwOffset part
#define FLD_DWOFFSET(dwOffset, bitStart, bitLen) dwOffset
// define a bit field
#define CFGCAP_DEVCTRL FLDARGS(2, 16, 4)
// in a function:
uint32_t dwAddr = addr/4;
// compare just the dwOffset part
if(dwAddr == FLD_DWOFFSET( CFGCAP_DEVCTRL ))
{
// do something
}
I expected this to expand like:
CFGCAP_DEVCTRL = 2, 16, 4
FLD_DWOFFSET( CFGCAP_DEVCTRL ) = 2
I get the gcc error:
error: macro "FLD_DWOFFSET" requires 3 arguments, but only 1 given
if(dwAddr == FLD_DWOFFSET( CFGCAP_DEVCTRL ))
^
error: ‘FLD_DWOFFSET’ was not declared in this scope
if(dwAddr == FLD_DWOFFSET( CFGCAP_DEVCTRL ))
Any help? Thanks.
Let's see how your macros are going to be processed:
if(dwAddr == FLD_DWOFFSET( CFGCAP_DEVCTRL ))
First, it tries to substitute the outermost macro, which is FLD_DWOFFSET. But it requires 3 arguments, when you only provide 1 (your inner macro isn't parsed at that moment yet). The preprocessor can't go any further, hence the error.
There is more relevant info here: http://gcc.gnu.org/onlinedocs/cpp/Macro-Pitfalls.html#Macro-Pitfalls
The macro pass expands macros in the order they're found. The first macro to be found is FLD_DWOFFSET( stuff ), which only sees one argument CFGCAP_DEVCTRL, and as a result cannot expand the FLD_DWOFFSET macro. It does not try to expand further macros until the current expansion is complete - in other words, it won't recognize that CFGCAP_DEVCTRL is a macro until it's finished expanding FLD_DWOFFSET, but it won't do that because you haven't provided enough arguments...
The other answers are correct in telling me why I can't do what I want to do. FLD_DWOFFSET is being evaluated with a single arg that isn't being expanded.
Here's my solution :
static inline uint32_t FLD_DWOFFSET(int dwOffset, int bitStart, int bitLen){return dwOffset;}
Hopefully this performs the same with optimization. Since it's a function, the macro argument (which expands to 3 args) is expanded before calling it.

Portable instrumentation

GCC has a nice feature about instrumentation which let you call a routine every time a function is called, or every time a function returns.
Now, I want to create my own system to make it portable to other compilers, and also to allow to instrumentalize the functions I want (which can vary in number of parameters), so I was thinking in two macro for both situations. I am thinking in making some kind of profile that it is activated only with a define clause.
#define FUNCT(t,function_name,...) \
(t) function_name(...) { \
(void) *func_pointer = &(function_name); \
start_data(func_pointer, myclock());
#define RETURN(x) {stop_data(func_pointer, myclock()); return (x);}
FUNCT(BOOL, LMP, const int prof, const int nmo))
if (nmo <= 5 ||
prof > (prof_l / 3)) {
.... do long operations....
RETURN(FALSE);
}
... do more....
RETURN(TRUE);
}
but I can’t get it to work. Can someone help me with this? or is this a difficult task to accomplish?
Other alternative that comes to my mind is let the function declare without a macro, and if it is anyway to know the function pointer without knowing its name, something like in VB when you call a Form with Me, with it is a generic alias. is it possible?
Use gcc -E to debug your macros. Using the code you posted:
$ gcc -E t.c
# ... skip stuff ....
(BOOL) LMP(...) { (void) *func_pointer = &(LMP);
start_data(func_pointer, myclock());)
if (nmo <= 5 ||
prof > (prof_l / 3)) {
.... do long operations....
{stop_data(func_pointer, myclock()); return (FALSE);};
}
... do more....
{stop_data(func_pointer, myclock()); return (TRUE);};
}
(I added some whitespace to make it readable.)
You can see two problems immediately: function arguments didn't get expanded as you thought they would, and there's an extra ) from somewhere.
To get the expanded variadic arguments, use __VA_ARGS__, not .... The stray ) is at the call site.
So:
#define FUNCT(t,function_name,...) \
(t) function_name(__VA_ARGS__) { \
(void) *func_pointer = &(function_name); \
start_data(func_pointer, myclock());
#define RETURN(x) {stop_data(func_pointer, myclock()); return (x);}
FUNCT(BOOL, LMP, const int prof, const int nmo)
if (nmo <= 5 ||
prof > (prof_l / 3)) {
.... do long operations....
RETURN(FALSE);
}
... do more....
RETURN(TRUE);
}
As to whether this is worth trying (variadic macros came with C99, not all compilers implement that standard, and support might vary from compiler to compiler), I'm not certain. You are probably better off using each compiler's native profiling tools - you'll get better results with hopefully less overhead.
It is much easier to instrument your functions at the calling side instead of the function side. A macro can have the same name as a function. Declare your replacement function somewhere
double myfunc_wrapper(int someArg) {
double ret = 0;
// do something before
...
// now call it
ret = (myfunc)(someArg);
// Then do something after
....
return ret;
}
Just to be sure put the () arround the call itself to be sure that always a function is called and not a macro.
And then "overload" your function with a macro
#define myfunc(...) mfunc_wrapper(__VA_ARGS__)
with that idea you can replace your function on the fly in the compilation units that interes you.
in addition to Mat, there is a ergonimical problem with using #define RETURN(x) {...}:
if (test)
RETURN (TRUE);
else
RETURN (FALSE);
will evaluate to
if (test)
{...}
; // <syntactical error
else
{...}
;

Resources