EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: Simon on October 30, 2019, 04:32:05 pm

Title: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Simon on October 30, 2019, 04:32:05 pm
So

Code: [Select]

#define start 0
#define Bn 3
uint8_t button_port[Bn];
button_port[start] = 0;


What did I do wrong? I hate GCC, it's error messages are cryptic and every time I do a new project just like another one in the past issue crop up that never did before.
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Simon on October 30, 2019, 04:33:41 pm
Oh and 0 is an invalid initializer, so is 1 and 2.
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: IanB on October 30, 2019, 04:34:04 pm
Try this:

Code: [Select]
#define SIZE 1
uint8_t button_port[SIZE];
button_port[0] = 0;
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Simon on October 30, 2019, 04:36:48 pm
Sorry I got myself in a muddle, the array size is declared as 3. I corrected it.
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: andersm on October 30, 2019, 09:26:31 pm
You're not trying to assign to the array outside a function, are you?
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Simon on October 31, 2019, 07:30:09 am
well yea. The array has a static value setup at the beginning of the program and does not change. Should I specify it as a constant or static?
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: oPossum on October 31, 2019, 07:38:54 am
Code: [Select]
uint8_t const button_port[Bn] = { 0, 0, 0 };
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Simon on October 31, 2019, 08:14:55 am
OK, but I still don't understand why the array is failing does it need to be in the main function at least? I was trying to create a separate file that I can include in any project that handles button presses - not possible?
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: andersm on October 31, 2019, 09:04:40 am
OK, but I still don't understand why the array is failing does it need to be in the main function at least?
The language rules do not allow it. If you want to initialize the contents of the array you must either do it as part of the definition, like in oPossum's post, or inside a function before it's used. But also remember that all global and static variables are initialized to zero by default.
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Siwastaja on October 31, 2019, 09:05:48 am
Assignment operation needs to be done in a function. Any function works.

x = y; generates code - instructions. They need to be somewhere. In C, you can't have free-hanging code. If you did, when would it run? If you want to run it "at the start", main() function is for this purpose.

OTOH,
type x = y;
is a definition with initialization; it will reserve memory, and the compiler handles the code that runs before the main() to actually make it initialized. oPossum has shown how to initialize an array. For a complex initialization, you may need to do "with code", that would  be in the beginning of main(), for example. The C standard specifies that your compiler will generate code that initializes all global (and static, inside functions) variables to zero. So if you need zero initialization to all members, just do:

uint8_t button_port[Bn];

If one of the members need to be something else, it's not bad to just overwrite that one in the beginning of main().
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Simon on October 31, 2019, 09:22:43 am
Of course yes. I had forgotten that putting code in a *.c file is not putting it in main().
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Ian.M on October 31, 2019, 09:23:57 am
As Siwastaja just pointed out,
Code: [Select]
button_port[0] = 0;
is a statement.  Statements are not allowed outside of functions, (and would be unreachable there anyway), so the compiler attempted to interpret it as a declaration or definition, saw the = and decided it was a definition with initialisation, and complained its invalid, as per the error message.

For your button input driver, if you need to do anything more complex than initialise your arrays with fixed values, you'll need an initialiser function, (which should *NOT* be in your #included header*),  to be called near the beginning of the main() function of your user program.

Its *RARE* for a single header file to be portable between projects - normally the smallest package that is, is a C source file and a header declaring its interfaces.

* see: https://www.gamedev.net/articles/programming/general-and-gameplay-programming/organizing-code-files-in-c-and-c-r1798/ (https://www.gamedev.net/articles/programming/general-and-gameplay-programming/organizing-code-files-in-c-and-c-r1798/)
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Twoflower on October 31, 2019, 09:29:09 am
An alternative to oPossums code:
Code: [Select]
#define Bn (3)
uint8_t const button_port[Bn] = { 0 };
With this code you only need to change the define if the Bh needs to be changed.
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Siwastaja on October 31, 2019, 01:19:07 pm
An alternative to oPossums code:
Code: [Select]
#define Bn (3)
uint8_t const button_port[Bn] = { 0 };
With this code you only need to change the define if the Bh needs to be changed.

Note that this initializes button_port[0] to 0, explicitly, and the rest to 0, implicitly. So you do the same initialization, in two different ways, combined in one command. IMHO, this may be confusing.

If you really want to initialize everything to 0, just omit the initializer; the C standard initializes all global data to zero.

If you wanted to change the table initialization to, say, 1, an inexperienced programmer in hurry might try to change that 0 to 1, assuming the whole table changes in a nice generic way. But it won't - only the first item changes, the array will be 1,0,0. Hence, it's better to leave the explicit initialization out completely, forcing you to think about it if you need to change the initial value (adding a for loop in the beginning of main is a viable generic option, then).

Also, at least some compilers seem to put all explicitly initialized data to the .data section, even if initialized to zero, wasting flash storage. When implicitly initialized to zero, it goes to .bss, without flash storage required.
Title: Re: button_port[start] = 0; has no storage class...... and conflicting data types
Post by: Twoflower on November 02, 2019, 01:07:11 pm
Siwastaja is right, the explanations in the Web are not pointing this out and I fell for it. It's get more clear if you do something like uint8_t const button_port[Bn] = { 2 }; and the resulting array is 2, 0, 0.

Depending on the compiler (gcc and clang seem to support this) a construct using designators to specify an area can be used:
Code: [Select]
#define Bn (3)
uint8_t const button_port[Bn] = { [0 ... Bn-1] = 2};
This will initialize the complete array to 2.

But I would not use that as this seems an extension of some compilers and is, to my understanding, not covered by the standard.