2

I have a structure which is:

typedef struct {
    GPIO_TypeDef* port;
    uint16_t pin;
} btn;

Some definitions:

#define BTN0    {App_BTN_GPIO_Port, App_BTN_Pin}
#define BTN1    {Calibration_BTN_GPIO_Port, Calibration_BTN_Pin}
//...

An array of buttons:

btn btns[] = {BTN0, BTN1, ...}

Also a function:

bool checkPressAndReleaseWithMask(btn button){
    if (HAL_GPIO_ReadPin(button.port, button.pin) == GPIO_PIN_RESET) {
        //bla bla bla
    }
}

I have the below problem. When I want to call this function, I can't pass my definitions:

btn find1BTN()
{
    btn test = {App_BTN_GPIO_Port, App_BTN_Pin};
    
    if(checkPressAndReleaseWithMask(btns[0])){ //allright

    } else if (checkPressAndReleaseWithMask(test)){ //allright
        
    } else if (checkPressAndReleaseWithMask(BTN0)){ //PROBLEM
        
    }
    
    return test;
}

btn[0] and test work fine, but the BTN0 does not. I've also tried:

    if (checkPressAndReleaseWithMask({.port = App_BTN_GPIO_Port, .pin = App_BTN_Pin})){ //PROBLEM
            
    }

The same compile-time problem:

error: expected expression

Why does this happen? What's the difference between BTN0 and btn[0]? They seem to be the same!

How about the {.port = App_BTN_GPIO_Port, .pin = App_BTN_Pin}? As I remember, we could pass structs this way, couldn't we?

I also checked this. It was not my problem.

NOTE: Feel free to change the topic. I couldn't find any better one.

Mohammad Kholghi
  • 533
  • 2
  • 7
  • 21

1 Answers1

3

The correct syntax for a compound literal is:

( type ) { initializer-list }

So the code needs to be:

checkPressAndReleaseWithMask((btn)BTN0);

Or

#define BTN0 ((btn){App_BTN_GPIO_Port, App_BTN_Pin})
checkPressAndReleaseWithMask(BTN0);
kaylum
  • 13,833
  • 2
  • 22
  • 31
  • Thanks, but why can I add them to the `btn btns[]` without type casting? – Mohammad Kholghi Aug 15 '21 at 07:56
  • 1
    Because that is a variable with a know type. Whereas `{ .. }` is a literal value of unknown type. To make it a valid compound literal you need to tell the compiler what the type of that literal is (and because the C language specification says you need to). – kaylum Aug 15 '21 at 07:58
  • 1
    @MohammadKholghi It looks like a typecast, but compound literals are different from casts. – mediocrevegetable1 Aug 15 '21 at 08:02
  • @mediocrevegetable1 Thanks. I just read about them. Do compound literals take a new memory every time I call them? – Mohammad Kholghi Aug 15 '21 at 08:21
  • @MohammadKholghi I beliee they do. For `struct` compound literals I think they are destroyed pretty soon though according to how they work in https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html – mediocrevegetable1 Aug 15 '21 at 08:30
  • @mediocrevegetable1 Thank you. I have memory limits. Are global variables a good idea, as they just occupy memory once? – Mohammad Kholghi Aug 15 '21 at 08:39
  • 1
    @MohammadKholghi I suppose so if stack space is a big concern. Every time you make a compound literal you're essentially making a local variable that might even just get destroyed _before_ the program exists the scope it was defined in. But if you really need to keep stack memory low then yeah, a global variable would work. – mediocrevegetable1 Aug 15 '21 at 08:45
  • 1
    A compound literal outside the body of a function has static storage duration; it exists during all of program execution. A compound literal inside a function has automatic storage duration associated with its enclosing block. – Eric Postpischil Aug 15 '21 at 11:09
  • @EricPostpischil unless I'm interpreting what you're saying incorrectly, the GCC page I previously linked says that an outside-of-body compound literal is an extension: _"As a GNU extension, GCC allows initialization of objects with static storage duration by compound literals (which is not possible in ISO C99 because the initializer is not a constant)."_ And when I try using a compound literal outside a function it does indeed give a `-Wpedantic` error: https://godbolt.org/z/47nfcrW97 – mediocrevegetable1 Aug 15 '21 at 15:05
  • 1
    @mediocrevegetable1: Whether an object with static storage duration can be initialized with a compound literal and whether a compound literal can appear outside a body of a function are separate questions. – Eric Postpischil Aug 15 '21 at 15:13
  • @EricPostpischil ah, you're right. I was thinking that it was impossible to have a compound literal outside a function body without initializing a static duration object, but I realize now that there are indeed cases where it's possible like `const char *a = (const char []){"Hello"};`. Sorry about that. – mediocrevegetable1 Aug 15 '21 at 15:19