Author Topic: [GCC] can't make a calculation as part of variable setup  (Read 10900 times)

0 Members and 1 Guest are viewing this topic.

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
[GCC] can't make a calculation as part of variable setup
« on: August 10, 2018, 08:22:02 am »
Code: [Select]
const uint8_t ADC_resolution = 13;
uint8_t speed_0 = 0;                                         // Percentage of speed
uint16_t speed_0_ADC = (speed_0 * (2^ADC_resolution / 100)); // Pre-calculated value of ADC
uint8_t speed_1 = 50;                                        // Percentage of speed
uint16_t speed_1_ADC = (speed_1 * (2^ADC_resolution /100));  // Pre-calculated value of ADC
uint8_t speed_2 = 99;                                        // Percentage of speed
uint16_t speed_2_ADC = (speed_2 * (2^ADC_resolution / 100)); // Pre-calculated value of ADC

const uint8_t good_button_press = 50;
const uint8_t startup_state = 0;
uint8_t button_counts;
uint8_t button_state = startup_state;
uint8_t fan_speed;
uint8_t current_fan_speed_input;
uint8_t analogue_fan_channel_timer;

Any assignment that requires a calculation throws up an error: Error      initializer element is not constant.

Should I just carry out the calculation on a new line?
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11859
  • Country: us
Re: [GCC] can't make a calculation as part of variable setup
« Reply #1 on: August 10, 2018, 08:25:22 am »
Any assignment that requires a calculation throws up an error: Error      initializer element is not constant.

Should I just carry out the calculation on a new line?

No, that won't work. You need to make sure the initialization expression only contains constants and no variables.

Alternatively you can have a separate initialization method in your code that happens one time to do the initial setup.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: [GCC] can't make a calculation as part of variable setup
« Reply #2 on: August 10, 2018, 08:28:45 am »
It's the statements that setup the variables that cause the problem:

uint16_t speed_1_ADC = (speed_1 * (2^ADC_resolution /100));
uint8_t button_state = startup_state;

I am assigning the values of constants to variable, what is the problem.
 

Offline johnwa

  • Frequent Contributor
  • **
  • Posts: 255
  • Country: au
    • loopgain.net - a few of my projects
Re: [GCC] can't make a calculation as part of variable setup
« Reply #3 on: August 10, 2018, 08:30:33 am »
I think you will find that the caret ('^') operator doesn't do what you think it does...
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: [GCC] can't make a calculation as part of variable setup
« Reply #4 on: August 10, 2018, 08:32:37 am »
it's not an exponent ?

is uint16_t suitable for a constant?
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13742
  • Country: gb
    • Mike's Electric Stuff
Re: [GCC] can't make a calculation as part of variable setup
« Reply #5 on: August 10, 2018, 08:33:15 am »
C treats consts like variables, and doesn't always understand that they can never change

Change the consts to #defines e.g.

const uint8_t ADC_resolution = 13;

to

#define ADC_resolution 13
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11859
  • Country: us
Re: [GCC] can't make a calculation as part of variable setup
« Reply #6 on: August 10, 2018, 08:37:41 am »
It's the statements that setup the variables that cause the problem:

uint16_t speed_1_ADC = (speed_1 * (2^ADC_resolution /100));
uint8_t button_state = startup_state;

I am assigning the values of constants to variable, what is the problem.

Well, for example, speed_1 is not a constant and yet you are trying to use it in an initialization expression. That is why the compiler is objecting. Same with speed_0 and speed_2.
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11859
  • Country: us
Re: [GCC] can't make a calculation as part of variable setup
« Reply #7 on: August 10, 2018, 08:38:54 am »
C treats consts like variables, and doesn't always understand that they can never change

I don't agree with this. Constant is as constant does. Using #define won't solve the problem, and will make the code harder to debug and test later on.
 

Offline johnwa

  • Frequent Contributor
  • **
  • Posts: 255
  • Country: au
    • loopgain.net - a few of my projects
Re: [GCC] can't make a calculation as part of variable setup
« Reply #8 on: August 10, 2018, 08:41:31 am »
it's not an exponent ?

is uint16_t suitable for a constant?

'^' is bitwise exclusive OR. There is a pow() function in the standard library , which works on doubles, but if you just want an integer power of 2, the left shift operator '<<' works well (at least, for unsigned quantities.) For 2^4, say, use '1 << 4'.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: [GCC] can't make a calculation as part of variable setup
« Reply #9 on: August 10, 2018, 08:42:22 am »


Well, for example, speed_1 is not a constant and yet you are trying to use it in an initialization expression. That is why the compiler is objecting. Same with speed_0 and speed_2.

even if i make it a constant i get the same.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: [GCC] can't make a calculation as part of variable setup
« Reply #10 on: August 10, 2018, 08:43:49 am »
C treats consts like variables, and doesn't always understand that they can never change

Change the consts to #defines e.g.

const uint8_t ADC_resolution = 13;

to

#define ADC_resolution 13


i originally did that and it compiled ok but am told that it's not good practice and i can see that it can mask problems. Every time I try to follow best practice I land in more trouble.
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11859
  • Country: us
Re: [GCC] can't make a calculation as part of variable setup
« Reply #11 on: August 10, 2018, 08:44:47 am »
I think you will find that the caret ('^') operator doesn't do what you think it does...

it's not an exponent ?

No...  :(

For powers you need to use the pow() function.

(Or what johnwa said)
« Last Edit: August 10, 2018, 08:47:33 am by IanB »
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11859
  • Country: us
Re: [GCC] can't make a calculation as part of variable setup
« Reply #12 on: August 10, 2018, 08:49:53 am »
even if i make it a constant i get the same.

If you replace this:

Code: [Select]
uint16_t speed_0_ADC = (speed_0 * (2^ADC_resolution / 100));
with this:

Code: [Select]
uint16_t speed_0_ADC = (0 * (2^ADC_resolution / 100));
It still doesn't compile?
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: [GCC] can't make a calculation as part of variable setup
« Reply #13 on: August 10, 2018, 08:52:15 am »
even if i make it a constant i get the same.

If you replace this:

Code: [Select]
uint16_t speed_0_ADC = (speed_0 * (2^ADC_resolution / 100));
with this:

Code: [Select]
uint16_t speed_0_ADC = (0 * (2^ADC_resolution / 100));
It still doesn't compile?

Than does, so it is complaining that a constant is not a constant!

Code: [Select]
const uint8_t speed_0 = 0;                                         // Percentage of speed
uint16_t speed_0_ADC = (speed_0 * (((1 << ADC_resolution) - 1) / 100)); // Pre-calculated value of ADC
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4028
  • Country: nz
Re: [GCC] can't make a calculation as part of variable setup
« Reply #14 on: August 10, 2018, 08:57:19 am »
This is fine with g++:

Code: [Select]
#include <inttypes.h>

const uint8_t ADC_resolution = 13;
const uint8_t speed_0 = 0;                                         // Percentage of speed
const uint16_t speed_0_ADC = (speed_0 * ((1<<ADC_resolution) / 100)); // Pre-calculated value of ADC
const uint8_t speed_1 = 50;                                        // Percentage of speed
const uint16_t speed_1_ADC = (speed_1 * ((1<<ADC_resolution) /100));  // Pre-calculated value of ADC
const uint8_t speed_2 = 99;                                        // Percentage of speed
const uint16_t speed_2_ADC = (speed_2 * ((1<<ADC_resolution) / 100)); // Pre-calculated value of ADC

const uint8_t good_button_press = 50;
const uint8_t startup_state = 0;
uint8_t button_counts;
uint8_t button_state = startup_state;
uint8_t fan_speed;
uint8_t current_fan_speed_input;
uint8_t analogue_fan_channel_timer;
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: [GCC] can't make a calculation as part of variable setup
« Reply #15 on: August 10, 2018, 08:59:02 am »
right:

project_variables.h
Code: [Select]
extern const uint8_t ADC_resolution;
extern const uint8_t startup_state;
extern const uint8_t speed_0;                                // Percentage of speed
extern const uint16_t speed_0_ADC;   // Pre-calculated value of ADC
extern const uint8_t speed_1;                              // Percentage of speed
extern const uint16_t speed_1_ADC;   // Pre-calculated value of ADC
extern const uint8_t speed_2;                              // Percentage of speed
extern const uint16_t speed_2_ADC;   // Pre-calculated value of ADC

project_variables.c
Code: [Select]
const uint8_t ADC_resolution = 13;
const uint8_t speed_0 = 0;                                         // Percentage of speed
const uint16_t speed_0_ADC = (speed_0 * (((1 << ADC_resolution) - 1) / 100)); // Pre-calculated value of ADC
const uint8_t speed_1 = 50;                                        // Percentage of speed
const uint16_t speed_1_ADC = (speed_1 * (((1 << ADC_resolution) - 1) / 100));  // Pre-calculated value of ADC
const uint8_t speed_2 = 99;                                        // Percentage of speed
const uint16_t speed_2_ADC = (speed_2 * (((1 << ADC_resolution) - 1) / 100)); // Pre-calculated value of ADC


const uint8_t startup_state = 0;
uint8_t button_state = startup_state;

won't compile.
« Last Edit: August 10, 2018, 09:00:59 am by Simon »
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13742
  • Country: gb
    • Mike's Electric Stuff
Re: [GCC] can't make a calculation as part of variable setup
« Reply #16 on: August 10, 2018, 09:03:42 am »
C treats consts like variables, and doesn't always understand that they can never change

Change the consts to #defines e.g.

const uint8_t ADC_resolution = 13;

to

#define ADC_resolution 13


i originally did that and it compiled ok but am told that it's not good practice and i can see that it can mask problems. Every time I try to follow best practice I land in more trouble.

Whenever I hear people saying things are "best practice" it usually turns out they don't understand the problem or haven't given it any thought.
There is almost never a "best" way to do something, only more or less applicable to a particular situation.

Some older compilers would actually copy const variables to RAM at startup, so using const rather than #define would be actively bad compared to using #define.

What problem exactly would it mask ?
 
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 
The following users thanked this post: Siwastaja

Offline hans

  • Super Contributor
  • ***
  • Posts: 1637
  • Country: nl
Re: [GCC] can't make a calculation as part of variable setup
« Reply #17 on: August 10, 2018, 09:04:23 am »
A classical discrepency between the GCC and G++ compilers. With godbolt.org, I noticed that this code (@brucehoult) will compile in GCC8.x and up, but not on older versions. On the other hand, it works in even the oldest G++ compilers.

However.. before GCC8.x flows downstream to IDE packages, you probably have to wait half a dozen years.
And I wouldn't recommended switching over a whole project to G++ because of this. That compiler is a bit stricter and your project may not compile (properly - under optimizations) elsewhere.

I would recommended replacing the "constants" with a macro in this case.
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13742
  • Country: gb
    • Mike's Electric Stuff
Re: [GCC] can't make a calculation as part of variable setup
« Reply #18 on: August 10, 2018, 09:07:37 am »
And with constants you also have to dick about with externs (or put them in a header file).
You probably want constants like this in a header file anyway so all compile-time opitons are in the same place and not scattered throughout the code

For this situation. #define works just fine, if not better.

Just do it and get on with the job instead of worrying about what language purists think is good or bad practice.
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3785
  • Country: de
Re: [GCC] can't make a calculation as part of variable setup
« Reply #19 on: August 10, 2018, 09:11:38 am »
Simon, that will not work. The language specification says the following about const:

Quote
Notes

C adopted the const qualifier from C++, but unlike in C++, expressions of const-qualified type in C are not constant expressions; they may not be used as case labels or to initialize static and thread storage duration objects, enumerators, or bit field sizes. When they are used as array sizes, the resulting arrays are VLAs.

What const in C means is that you cannot modify that variable after it has been initialized (when used as an l-value). When const variable appears on the right side (r-value) of the assignment, the const is effectively ignored. That's why you cannot do what you are trying to do.

See here:
https://en.cppreference.com/w/c/language/const

BTW, calculating that value 2**ADC_resolution like that repeatedly is a bit silly - that value is a constant, why don't you precalculate that?
 
The following users thanked this post: Siwastaja, newbrain

Offline hans

  • Super Contributor
  • ***
  • Posts: 1637
  • Country: nl
Re: [GCC] can't make a calculation as part of variable setup
« Reply #20 on: August 10, 2018, 09:13:33 am »
Well , in another thread we ranted a lot about the pitfalls of macro's.. I don't like them, but in a GCC environment like this there is not better alternative.
Still points up for writing down formulas in code, rather than the calculated values. It's more flexible, and the formula itself is already documentation rather than some "magic" number.

You could write the formula in a function, but then you're not creating a const setup value. A compiler can optimize this away, though. But using a macro will probably yield the most deterministic code in terms of performance, as it needs to be fully evaluated irrelevant of optimization levels.

If you only use this value at 1 location in your program (e.g. at initialization of peripherals), you could also do the calculation inside that function. Arguably a bit nicer than littering the program with more global variables.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: [GCC] can't make a calculation as part of variable setup
« Reply #21 on: August 10, 2018, 09:16:44 am »
I am trying to initialise it but i can't even do that. I declare the const name and then it won't take the value assingned. If i make the calculated value a variable instead the error is the same.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: [GCC] can't make a calculation as part of variable setup
« Reply #22 on: August 10, 2018, 09:18:47 am »
Well , in another thread we ranted a lot about the pitfalls of macro's.. I don't like them, but in a GCC environment like this there is not better alternative.
Still points up for writing down formulas in code, rather than the calculated values. It's more flexible, and the formula itself is already documentation rather than some "magic" number.

You could write the formula in a function, but then you're not creating a const setup value. A compiler can optimize this away, though. But using a macro will probably yield the most deterministic code in terms of performance, as it needs to be fully evaluated irrelevant of optimization levels.

If you only use this value at 1 location in your program (e.g. at initialization of peripherals), you could also do the calculation inside that function. Arguably a bit nicer than littering the program with more global variables.

The code is designed so that I can use any ADC resolution I like. By changing the one number all constants will adjust as will the oversampling algorithm and anything else.
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3785
  • Country: de
Re: [GCC] can't make a calculation as part of variable setup
« Reply #23 on: August 10, 2018, 09:20:44 am »
Also, re #define vs const:

Using #define (preprocessor macro) for constants is a bad practice because the compiler has no way to check the type of the value. #define is basically string replacement/concatenation before even the compiler sees it. So if someone #defines the constant to something unexpected or invalid, you are going to have a much harder time trying to find the problem - typical problem when changing between compilers. Relying on certain compiler behaviour (e.g. GCC) is a way to hell - when you will have to change to a non-GCC compiler for whatever reason (Visual C+++, clang, Microchip's PIC compilers, etc.) you will suffer.

In C using #define macros for constants is the idiomatic solution because of exactly the problem you are facing (const doesn't declare a "constant" only that the given block of memory cannot be changed after initialization). Newer revisions of C++ use constexpr declaration to explicitly tell the compiler that something is constant at compile time - with that your code would work just fine. C doesn't have that, unfortunately.

 
The following users thanked this post: oPossum, newbrain

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3785
  • Country: de
Re: [GCC] can't make a calculation as part of variable setup
« Reply #24 on: August 10, 2018, 09:24:17 am »

The code is designed so that I can use any ADC resolution I like. By changing the one number all constants will adjust as will the oversampling algorithm and anything else.

Then calculate that value once (it is the same value for all instances where you use it) and use the calculated value multiple times. Doing this at runtime, especially on a microcontroller, is a pretty expensive operation for no reason.

But anyway, you can't write the code the way you want - you need to either switch to C++ and use constexpr (assuming your toolchain is modern enough to handle it) or you will have to precalculate these values/use macros because C doesn't allow non-constant expressions in the initializers (const foo is not a constant expression!)
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf