Hello, In trying to compile the C code with the C51 compiler [Keil µvision2], I received error c213 "left side of asn-op not an lvalue" - " the address of a changeable object is required at the right side of the assignment operator". But i don't know where is/are problems... Code: #include <Chipcon\srf04\regssrf04.h> #include <Chipcon\srf04\halsrf04.h> #include <Chipcon\srf04\ebsrf04.h> #include <ctype.h> #define TX_entree 0x80 //P0.4 #define RI0 0x98 BYTE idata txBuffer[8]; BYTE idata buffer[8]; int i = 0; int taille_tab; void main () { #ifdef STAND_ALONE CLOCK_INIT(); IO_PORT_INIT(); #endif ebLcdInit(); ebLcdUpdate("Emission test v0.1", NULL); halWait(3000); ebLcdUpdate("Initialisation", NULL); halWait(2000); halUartSetup(UART_BAUDRATE_115200, DEFAULT_MODE); SPI_INIT(SCLK_6_MHZ); POWER_UP_RESET_CCxxx0(); FIRST ERROR UART_RX_ENABLE(); ebLcdUpdate("Reception et stockage des données en cours", NULL); halWait(3000); if(RI0 == 1){ //stockage des données taille_tab = sizeof(buffer); for (i = 1; i < taille_tab; i++) { UART_WAIT_AND_RECEIVE(buffer[i]); SECOND ERROR IF I COMMENT THE FIRST } } ebLcdUpdate("Emission des données en cours", NULL); halWait(2000); SPI_ENABLE(); halRfSendPacket(buffer, sizeof(buffer)); ebLcdUpdate("Fin", NULL); halWait(2000); } Any help or comments appreciated. I'm workin' on the CC2500DK, it's an tranceiver HF and many fonctions has already created by the constructor. Thanks John
POWER_UP_RESET_CCxxx0(); FIRST ERROR Where is the proto? Erik
the proto is in library halsfr04.h. So the define is: #define POWER_UP_RESET_CCxxx0() \ do { \ NSSMD0 = 1; \ halWait(1); \ NSSMD0 = 0; \ halWait(1); \ NSSMD0 = 1; \ halWait(41); \ RESET_CCxxx0(); \ } while (0) and RESET_CCxxx0() in same lib : #define RESET_CCxxx0() \ do { \ NSSMD0 = 0; \ SPI0DAT = CCxxx0_SRES; \ SPI_WAIT(); \ while (P0_1); \ NSSMD0 = 1; \ } while (0) Thx, John.
do { .... } while (0) That's a new one. Just curious, what is the purpose of such a construct? Erik
It's a horrible macro dodge: http://www.eskimo.com/~scs/C-faq/q10.4.html
It's a horrible macro dodge: You got that right "The usual goal is to write a macro that can be invoked as if it were a statement consisting of a single function call" Got it, it must be an entry from the "if C is readable, it is not real C" club. Hiding the fact that something is a macro by making it look as a subroutine will make debugging pure joy. Erik
Erik, I actually think this sort of thing is justifiable if you comment it up properly. For instance, it can achieve the equivalent of C++'s "inline" functions in C. If you have a "function" to call a bunch of places that's very simple, then just injecting the 9 or 10 actual instructions everywhere gets a bit ugly. Also, if the timing is of some importance, they may be used at places where you don't want the overhead of a function call.
For the purposes of debugging, you should take your macro "calls" and replace them with the individual construct. That is, put the defined do{}while(0); in the main code and try to compile it rather than using the macros. My suspicion is that when you do this, it will reveal something about the way the compiler is interpreting your macros, and you'll see where the real problem lies.
I actually think this sort of thing is justifiable if you comment it up properly. For instance, it can achieve the equivalent of C++'s "inline" functions in C. If you have a "function" to call a bunch of places that's very simple, then just injecting the 9 or 10 actual instructions everywhere gets a bit ugly. Also, if the timing is of some importance, they may be used at places where you don't want the overhead of a function call. You totally do not get the point, nobody (or at lest not I) have a problem with using a macro to achieve the above. The issue is "making the macro look like a function call" which is a wonderful way to obfusciate the code. Erik
"The issue is "making the macro look like a function call" which is a wonderful way to obfusciate the code." I don't know, the caps in the macro name scream 'MACRO!' to me.
....obfusciate the code." I don't know, the caps in the macro name scream 'MACRO!' to me. If you "scream" macro, the why use the do_while_0 which have no other purpose than to make it look like a function call? Erik
Many C programmers do not realize that you can declare local blocks inside functions. That is,
void main (void) { int i; // code goes here { // local block int j; // some code } // end of local block // more code goes here } // main
switch (msg->type) { case MsgTypeA : { MsgA* msgA = (MsgA*)msg; // variables for handling msg A msgA->fieldA... } break; case MsgTypeB : { MsgB* msgB = (MsgB*)msg; // vars needed only for B msgB->fieldB... } break; default : break; }
Erik, I understand now. Leaving off the () at the end would be a nice way to clue people in that it was a macro, I agree.
Another place I find local blocks handy is in switch statements. Well I guess we know Drew is among those of us with the misfortune to have written a Windows WndProc or two. :)
The issue is "making the macro look like a function call" which is a wonderful way to obfusciate the code. You've let yourself get confused. This is not about adding obfuscation, but about keeping it under control. The goal of the do..while(0) trick is not to make the macro call look like a function call --- the mere fact of it being a function-like macro with a parameter list already achieves that. The actual goal is to make the macro invocation not just look like a function call (including an argument list), but also actually act like one, in all possible contexts. The tricky one being
if (foo) MYMACRO(bar,2,3,4); else do_something_else(bar,4,3,2);