This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Error C213

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:

    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.

  • 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
    

    is perfectly legal syntax. I've often seen people wrap their macro body in a do-while(0) just to get a local block that executes once. Just the curly braces will do in most cases.

    Another place I find local blocks handy is in switch statements.

        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;
            }
    

    The example casts shown presume that each message type has its own structure definition for the contents of that message. The cast just cleans up syntax within the block. A good compiler will notice that there's really only one "msg" variable here, and that the difference is all source-level semantics.

    One caveat for this sort of usage is that C51 doesn't seem to handle variable declarations in local blocks well. It essentially promotes the variables outside the block, so they occupy "stack" space for the entire existence of the function, rather than existing just in the scope of the local block. The variables from two such local blocks do not get overlaid, even though they could be, and so "stack" usage is higher than it could be (but no higher than if you omitted the local blocks entirely and moved the declarations up to the enclosing block).

  • 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);
    Only the do..while() trick allows to put a ';' after the macro call without getting the if/else all messed up. This is the main difference between the do-while trick and a simple pair of curly braces around the macro body.

    Now you may say, why would I care about the ability to put a ';' in there? Well, maybe you don't --- but at least some C-aware editors will cause considerable mayhem to the auto-indentation if you have C statements without closing semicolons.