This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

expression must be an lvalue or a function designator?

Guru 15580 points

I am getting the following compile error. Can someone help me decipher?

"../intc_arm.c", line 19: error: expression must be an lvalue or a function designator

Here's the offending line:

 

"sysISRtbl[AINTC_EVENTID_EDMA3_0_CC0_INT0] = &isr_edma_tcc();"

 

And here's the called function:

void isr_edma_tcc() //Incoming EDMA sample buffer ready (transfer complete)

{

data_available = true;

}

The sysISRtbl is from ARM9_handler.asm. The example in the header says:

; /*** Assign ISR to GPIOB0 ***/

; sysISRtbl[AINTC_GPIO_B0INT] = &GPIO_input_isr;

; /*** VBR Points to ISR Table ***/

; aintcRegs->VBR = (unsigned int) sysISRtbl;

....which is what I thought I was doing.

Can anyone give some guidance?

Thx,

MikeH

 

 

 

  • I am assuming that sysISRtbl is an array of function pointers. The this

    sysISRtbl[AINTC_EVENTID_EDMA3_0_CC0_INT0] = &isr_edma_tcc();

    should be

    sysISRtbl[AINTC_EVENTID_EDMA3_0_CC0_INT0] = isr_edma_tcc;

     

  • Norman,

    Wow, my own personal support guy!...:)

    Norman Wong said:
    sysISRtbl[AINTC_EVENTID_EDMA3_0_CC0_INT0] = isr_edma_tcc;

    I had tried that earlier but the to following error:

    "../intc_arm.c", line 26: error: a value of type "void" cannot be assigned to an entity of type "ISRpointer"

    Here are the various definitions relating to this problem. This is mostly from the edma3 example in rCSL;

    typedef volatile void (*ISRpointer);

    // ARM System Interrupt Table (Map System Interrupts to Corresponding ISRs)

    ISRpointer sysISRtbl[NUM_AINTC_EVENTID] = {NULL};

    ...and as shown earlier

    void isr_edma_tcc() //Incoming EDMA sample buffer ready (transfer complete)

    {

    data_available = true;

    }

    Guidance appreciated.

    Thx,

    MikeH

     

  • Stat holiday has taken the usual responders offline. I think you are missing the parameter list in the typedef:

    typedef volatile void (*ISRpointer)();
    ISRpointer sysISRtbl[NUM_AINTC_EVENTID] = {NULL};
    void isr_edma_tcc()
    {
    data_available = true;
    }

    I like to explicitly state that nothing is to be passed to a function.

    typedef volatile void (*ISRpointer)(void);
    ISRpointer sysISRtbl[NUM_AINTC_EVENTID] = {NULL};
    void isr_edma_tcc(void)
    {
    data_available = true;
    }

  • Norman,

    Adding the "void"s does not change the previously encountered error ("a value of type "void" cannot be assigned to an entity of type "ISRpointer""). Plus, the typedef was extracted verbatim from the working example (EDMA_ping_pong_armL138) project.

    Norman Wong said:
    Stat holiday has taken the usual responders offline

    Thanks for pitching in.

    MikeH

     

  • FOUND IT!

    " sysISRtbl[AINTC_EVENTID_EDMA3_0_CC0_INT0] = isr_edma_tcc();"

    should not have '()". It should be

    "" sysISRtbl[AINTC_EVENTID_EDMA3_0_CC0_INT0] = isr_edma_tcc;"

    Sometimes trying to interpret cryptic error codes can consume hours of wasted time.

    Thanks again!

    MikeH

     

  • My once solid understanding of C is getting shaky. I thought:

    typedef volatile void (*ISRpointer); // volatile pointer to void
    typedef volatile void (*ISRpointer)(); // volatile pointer to a function with no args

    My post above did remove the "&" and "()". Although on some compilers want the "&". But never the "()".

     

  • Norman,

    Norman Wong said:
    My once solid understanding of C is getting shaky

    Mine has (obviously) always been shaky. I've been spoiled by Microsoft's great development environment (Visual Studio) with comprehensive auto-complete and suggestions for error corrections.

    Thanks again!

    MikeH

     

  • Norman Wong said:

    typedef volatile void (*ISRpointer)(); // volatile pointer to a function with no args

    This one is not quite right.  It's actually a pointer to a function (taking unspecified parameters) and returning volatile void.  In this case, the "volatile" is useless.

    If you have access to "cdecl", you can use it to decipher C declarations.  (You may have to remove the keyword "typedef".):

    % cdecl explain "volatile void (*ISRpointer)(); "
    declare ISRpointer as pointer to function returning volatile void

    You can get it online, too:

    http://cdecl.org

  • This is going to be bit of diigression. You got me. Yeah, I'm playing a bit loose with the no arg vs unspecified args....when nothing is something wierdness. For completeness:

    typedef volatile void (*ISRpointer)(); // volatile pointer to a function with unspecified args
    typedef volatile void (*ISRpointer)(void); // volatile pointer to a function with no args

    I've never quite understood why the "unspecified" form still exists in this day of strongly typed methodologies. Rarely ever seen anybody prototype as unspecified args and then proceed to implement with some args. The "()" form gets to be synonymous  with "(void)".

    More digression. For me, it makes wonder why the TI compiler allows the address function to be a assigned to a variable of type:

    typedef volatile void (*ISRpointer);

    Thanks for the cdecl.org link. It will be quite useful.

  • Norman Wong said:

    I've never quite understood why the "unspecified" form still exists in this day of strongly typed methodologies. Rarely ever seen anybody prototype as unspecified args and then proceed to implement with some args. The "()" form gets to be synonymous  with "(void)".

    Because there is a lot of old C code still in use which doesn't specify the parameters.  When code works, there is tremendous resistance to updating it, and so the compiler is obliged to allow it.

    Norman Wong said:

    For me, it makes wonder why the TI compiler allows the address function to be a assigned to a variable of type:

    typedef volatile void (*ISRpointer);

    In strict ANSI mode (-ps), it doesn't allow this without an explicit cast.  I'm a little surprised that we don't emit a warning or remark in default mode.

    cl6x xx.c -ps
    "xx.c", line 3: error: a value of type "void (*)(void)" cannot be used to initialize an entity of type "volatile void *"
  • This is an answer that explains the specific error "expression must be an lvalue or a function designator", and gives a constructive way to handle such errors.

    I will describe how, to my understanding, the compiler handled the expression, according to appendix A in the second edition of "The C programming language", that describes the precedence of expression operators and thus, the sequence of the work of the compiler.

    I will quote, in pieces, the relevant section in K&R and explain how the compiler works to produce the error according to this section.

    Quote from K&R on the sequence of the work of the compiler
    "A7 Expressions
    The precedence of expression operators is the same as the order of the major subsections of this section, highest precedence first. Thus, for example, the expressions referred to as the operands of + (§A7.7) are those expressions defined in §§A7.I-A7.6."

    Qoute from K&R
    "A7.1 Ponter Generation
    Similarly, an expression of type "function returning T," except when used as the operand of the & operator, is converted to "pointer to function returning T."

    The compiler saw the function name and treated it as pointer to function returning T. writing ("= isr_edma_tcc;") would achieve the result of taking the address of the function. However the expression was "=&isr_edma_tcc();", and thus the compiler continued parsing it.

    Quote from K&R
    "A7.3 postfix expressions
    postfix -expression:
    primary-expression
    postfix-expression [ expression]
    postfix-expression ( argument-expression-list (optional)),
    postfix-expression . identifier
    postfix-expression -> identifier
    postfix-expression ++
    postfix-expression --

    . . .

    A7.3.2 function calls
    A function call is a postfix expression, called the function designator, followed by parentheses containing a possibly empty, comma-separated list of assignment expressions (§A7.17), which constitute the arguments to the function."

    The compiler continued its work and than saw the parenthesis and treated the expression "isr_edma_tcc()" as a function call.

    Quote from K&R "A7.4 Unary operators
    . . .
    unary-operator: one of & * + - ~"

    The compiler continues it's work and treated the '&'. However the unary operator '&' can be taken only on an lvalue expression, and a function designator "isr_edma_tcc()" is not an lvalue, (probably because the value returned from a nene void function call is in the stack)
    thus the compiler anounced the error. "expression must be an lvalue or a function designator".

  • "Although on some compilers want the "&". But never the "()"

    A quote from appendix A in K&R with my remarks in parenthesis.

    "A7.3.2 function calls
    In the first edition, the type was restricted to "function," and an explicit * operator was required to call through pointers to functions (This seems to be the reason why some of the compilers use the '&' character). The ANSI standard blesses the practice of some existing compilers by permitting the same syntax for calls to functions and to functions specified by pointers. The older syntax is still usable (and this can explain the two sorts of compilers).
  • "Although on some compilers want the "&". But never the "()"

    A quote from appendix A in K&R with my remarks in parenthesis.

    "A7.3.2 function calls
    In the first edition, the type was restricted to "function," and an explicit * operator was required to call through pointers to functions (This seems to be the reason why some of the compilers use the '&' character). The ANSI standard blesses the practice of some existing compilers by permitting the same syntax for calls to functions and to functions specified by pointers. The older syntax is still usable (and this can explain the two sorts of compilers).
  • "I've never quite understood why the "unspecified" form still exists in this day of
    strongly typed methodologies. Rarely ever seen anybody prototype as unspecified args
    and then proceed to implement with some args. The "()" form gets to be synonymous
    with "(void)"."

    "Because there is a lot of old C code still in use which doesn't specify the parameters.
    When code works, there is tremendous resistance to updating it, and so the compiler is
    obliged to allow it."


    A void value is nonexistent value and thus a function that does not receive parameters
    may have an empty parameters list which was before the insertion of the keyword void
    to the ANSI standard. or one nonexistent parameter (After the insertion of the keyword
    void to the ANSI standard).

    K & R A6.7 Void
    "The (nonexistent) value of a void object may not be used in any way, and neither
    explicit nor implicit conversion to any non-void type may be applied."
    . . .
    "void did not appear in the first edition of this book,but has become common
    since."

    In fact K & R says that the insertion of the nonexistent parameter was, in a way,
    forced on them, as a part of the most important language change introduced by the
    ANSI standard, which was, "function declarators with parameter prototypes."

    K & R in A8.6.3 Function Declarators
    "Some syntactic ugliness was required for the sake of compatibility,
    namely void as an explicit marker of new-style functions without parameters."

    It is good to know C89, because the notes (in the little letters) in Appendix A of K & R,
    help to understand the none standard behavior of compilers.
    However knowing C99 is more important, and C99 is only a little part of the knowledge
    needed for working with TI products, thus I refrained from this comment until now.
    However, with this comment, I add that I have no doubts that the talented and skilled people
    in this discussion, will learn faster and probably understand deeper the discussed subject,
    if and when they will see it as a priority.
    I hope that the important part, of spreading truth and seen respect accompanied with hidden
    encouragement, that are crucial in such discussions (not less than professionalism)
    is done in the right way, by me.