Good old macros and GCC - Page 1
Forum section: electronics / general

author: James
author_rank: Newbie
timestamp: July 30, 2011, 01:13:23 pm
content: I have been playing around with some macros in AVR studio and have hit a brick wall. From memory the statementCode:#define YOURCONSTANT 1assigns the value "1" to the constant "YOURCONSTANT".How ever, is there a way to use a variable in place of the "1" and assign its value to the constant? The idea is to allow software control through a function for exampleCode:something_init(unsigned char your_constant_value){#define YOURCONSTANT your_constant_valuereturn YOURCONSTANT;}Therefore if the value of your_constant_value is "hello" or "1", then the output of the function would be "hello" or "1".So far my macro has taken the variable name as the input and therefore outputs the name of the variable not its value (e.g the output as "your_constant_value" not "hello" or "1").It is propably just a misunderstanding of how macros work but if someone could please help that would be great.Thanks,James

author: Hideki
author_rank: Frequent Contributor
timestamp: July 30, 2011, 02:13:40 pm
content: Macros work by text substitution, so before the program is fed to the actual compiler, a preprocessor will replace all YOURCONSTANT with whatever text you define it to be.So in your example, the line:return YOURCONSTANT;will be changed into:return your_constant_value;

author: Unknown
author_rank: Unknown
timestamp: July 30, 2011, 02:46:55 pm
content: To add to what Hideki says, pre-processor directives like #define are, as the name suggests, interpreted by the pre-processor, which runs before the compiler. This pre-processor has no understanding of C, so putting a #define within a function doesn't make any difference. Most styles will only use #defines in header files to make them easier to find.You appear to attempt to abuse pre-processor directives as global variables, this won't work. Any Using YOURCONSTANT outside the something_init() function will cause the compiler to complain about an undefined variable 'your_constant_value'.Any proper C tutorial or textbook should explain how pre-processor directives work, and how they don't.

author: ruku
author_rank: Contributor
timestamp: July 30, 2011, 02:54:52 pm
content: Wikipedia has an excellent article on how things are handled in the C preprocessor.http://en.wikipedia.org/wiki/C_macro#Macro_definition_and_expansionTo the best of my knowledge, you can't change or re-assign the value of a constant. Otherwise, it wouldn't be... ...constant!I'm not quite sure what you're trying to attempt, but there are a few things you can try... One thing you can do is macro expansion.#define MAX(a, b) ((a > b) ? a : b)Note the parentheses around the whole expression. This keeps the expression from being affected by order of operation.You can also define a const variable, and allow the user (or coder) to set it once, but I'm not sure if that's what you're looking for. Global variables, perhaps?

author: Mechatrommer
author_rank: Super Contributor
timestamp: July 30, 2011, 07:40:24 pm
content: there's a proper way to do it, so use it!Code:something_init(unsigned char your_constant_value){unsigned char *YOURCONSTANT = &your_constant_value;return YOURCONSTANT;}put your runtime value in memory, not in #DEFINE, which stored compile time value/text.

author: Unknown
author_rank: Unknown
timestamp: July 30, 2011, 08:03:43 pm
content: IMO it's bad style to use full caps for YOURCONSTANT, which is not a constant in this case.Apart from style, your_constant_value is passed by value, so it's stored on the stack. What will happen to it when something_init() returns? YOURCOSTANT is just a pointer to your_constant_value, which will be pointed at unallocated memory at that point.

author: James
author_rank: Newbie
timestamp: July 31, 2011, 06:57:40 am
content: @MechatrommerTried the code but when compiling receive the error"expected identifier or '(' before numeric constant"I think it will just be easier to put all the defines in the header file so the values can be changed from there.Thanks everyone for your help,James

author: Mechatrommer
author_rank: Super Contributor
timestamp: July 31, 2011, 09:26:10 am
content: sorry i didnt bother to check my suggested code. but u'll never find a programmer that can do it in the first try, even bill gates. the word "program" will always side by side with the word "debug". so keep trying.

author: ejeffrey
author_rank: Super Contributor
timestamp: August 01, 2011, 08:44:02 am
content: FWIW, at least in C++ it is now 'preferred' to use const variables and inline functions instead of #define when possible, although plenty of people still do it the other way.For instance:Code:#define PI 3.1415#define AREA_OF_CIRCLE(r) (PI*r*r)vs.Code:const float PI=3.1415;inline float area_of_circle(float r) { return PI*r*r; }In the olden days, the former way was faster, but all C++ compilers will generate equivalent code. The advantages of the latter are that that you get better type checking, better error messages, and you can do thinks like take the address of the variable or function in cases where you need to pass pointers. In C you may have to use the former. The C89 standard doesn't officially include inline, and while most or all C compilers support it, their implementations may not be compatible.The most important use of #define is actually for conditional compilation using #if. If you have two versions of code and need to select which one is compiled on a given platform, you would use a #define variable. Other than that, #define macros are mostly only actually necessary when you are doing something really ugly that can't be accomplished in an inline function, like trying to imitate dynamic programming constructs in C.

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 01, 2011, 09:21:51 am
content: yes but inline cannot do...Code:#define MYLOOP1 for (i=0;i<10;i++) { \do some routine at beginning of loop if necessary; \#define MYLOOP2 do some routine at the end of loop; \}; // end of loop bracketmain() {MYLOOP1;// do somethingMYLOOP2;};i used this technique once, to make shortcut of alot of repeating same loop routine at the beginning of the loop throughout my code.

author: ejeffrey
author_rank: Super Contributor
timestamp: August 01, 2011, 09:52:06 am
content: That is what I would call a bad use of #define. Actually it is 'something really ugly that can't be accomplished in an inline function, like trying to imitate dynamic programming constructs in C.' Dynamic languages that support lambdas can do this kind of thing properly. C programmers are forced to make do with less powerful constructs or to abuse the preprocessor.In C, I would try to avoid this whenever possible. For the bare loop, it only saves a few keystrokes and significantly obfuscates the code. If you need the extra code at the beginning and end of a loop, you can either make those functions, or make the whole loop a function that takes a callback.Code:const int LOOP_MAX 10;for (i=0; i<LOOP_MAX; i++) {loop_enter(i);// CODE GOES HERE.loop_exit(i);}or:Code:int do_loop(int (*loop_callback)(int, float)){int i;float f=0;for (i=0; i<10; i++) {start_iteration();f=loop_calback(i,f);end_iteration();}}Function calls can't directly modify their calling environment or declare variables, so that is somewhat limiting compared to your example. Really, that is the whole idea: using inline functions where possible makes the code clearer and easier to debug because unwanted side-effects aren't hidden behind the macro. Sometimes you have no choice, but it is always worth thinking about whether you can achieve your goal without ugly preprocessor hacks.

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 01, 2011, 03:47:31 pm
content: there's performance penalty calling functions within a loop, esp that performs many thousands or millions of iterations. yes its ugly, but the only method i know for the construct hack if performance is important.

author: Bored@Work
author_rank: Super Contributor
timestamp: August 01, 2011, 04:05:09 pm
content: Quote from: Mechatrommer on August 01, 2011, 03:47:31 pmUse inline functions.

author: Semantics
author_rank: Contributor
timestamp: August 01, 2011, 04:17:06 pm
content: Quote from: BoredAtWork on August 01, 2011, 04:05:09 pmThis.Macros are evil. Well, not too evil but parameter expanded macros make it way too easy to add subtle bugs... see examples in the link.

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 01, 2011, 04:32:17 pm
content: Quote from: Semantics on August 01, 2011, 04:17:06 pmmaybe i'm the last breed (#define devil) who know exactly what that means.

author: ejeffrey
author_rank: Super Contributor
timestamp: August 01, 2011, 06:55:44 pm
content: Thats what they all say.