Author Topic: constants Array scope in "C'"  (Read 22116 times)

0 Members and 1 Guest are viewing this topic.

Offline gogomanTopic starter

  • Regular Contributor
  • *
  • Posts: 123
constants Array scope in "C'"
« on: December 26, 2018, 05:16:43 pm »
Hi  I need to use a constant array, Since the array is accessed by several functions it ended up in global space.   
 
     Under what conditions should constants be declared in global space?
     If the constant is declared  in main or in a function does it need to be declared as static?
 
     Execution Speed is a concern, is there a benefit between  local vs global scope?

 

thanks


 

Offline 0xdeadbeef

  • Super Contributor
  • ***
  • Posts: 1911
  • Country: de
Re: constants Array scope in "C'"
« Reply #1 on: December 26, 2018, 05:50:41 pm »
In C, the "const" classifier originally just  means that the value can't be changed after initialization. So the treatment of "const" depends on the compiler or its settings.
For a PC compiler, "const" just means that the compiler may optimize these values, i.e. they may not even appear in the mapfile anymore since the compiler replaced the const access by immediate values.

Forembedded compilers, there's at least a setting to put "const" values in ROM. This saves RAM and the copy of ROM to (initialized) RAM in the C runtime init isn't needed anymore.
So embedded programs tend to put data in ROM sections to save RAM. However, usually (S)RAM is faster than (Flash) ROM, so this typically comes at the cost of execution speed.

Using const arrays in a function (without static) usually means that the array is located on the stack and has to be initialized during runtime every time the function  is called. So this is typically a bad idea.
Anyway, if execution speed is a concern, don't put lookup tables etc. in ROM.
Trying is the first step towards failure - Homer J. Simpson
 

Offline hans

  • Super Contributor
  • ***
  • Posts: 1994
  • Country: 00
Re: constants Array scope in "C'"
« Reply #2 on: December 26, 2018, 09:02:24 pm »
Short answer: depends on compiler, architecture and settings

Longer answer:
Const means that the variable can only be assigned once and is then read-only. This does not mean that the compiler will put these variables in ROM. For example:
Code: [Select]
int foo(void) {
    static uint8_t i = 0;
    const uint8_t j = i*i;
    return j;
}
Will compile to a short assembly, as it always returns 0, despite variable i being marked static (keeps state across calls).

If you do change i, the compiler will still let variable j be marked "const" even though it needs to be calculated in run-time:
Code: [Select]
int foo(void) {
    static uint8_t i = 0;
    const uint8_t j = i*i;
    i++;
    return j;
}
This generates a lot of assembly code. If you want the compiler to truly evaluate as much expressions as possible during compilation (and otherwise throw an error), you could use C++'s constexpr instead of const. If you would change that for the code above, you would get an error:
Code: [Select]
<source>:5:29: error: the value of 'i' is not usable in a constant expression

     constexpr uint8_t j = i*i;
As it is indeed not intended..

In this case, "constexpr" is a quality of life thing. If you're using C, the best thing is to keep the code simple (as is always the case) and just assign const values to the array you've got.

The placement of the table may influence the address of the table in the code space. A compiler may be more tempted to put a global variable at the end of the program, after the code region(s). Typically what I see in ARM GCC is that it will also put constants nearby functions, for example 32-bit pointer locations, and then load data from it by relative positioning of PC register. In addition, as most ARM micro's use FLASH accelerators/cache, the spatial locality of these constants may help in reducing the number of random accesses to FLASH.

However if you put the same array in multiple functions, the compiler will likely put these arrays multiple times in your binary.

It also depends on your program if this is a big penalty hit. You could speed up the execution by processing samples in blocks, such that the constants only need to be loaded once for multiple samples.
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3916
  • Country: it
Re: constants Array scope in "C'"
« Reply #3 on: December 26, 2018, 09:49:25 pm »
Forembedded compilers, there's at least a setting to put "const" values in ROM. This saves RAM and the copy of ROM to (initialized) RAM in the C runtime init isn't needed anymore.

Fun fact, with the Mikro C compiler for microchip PIC it used to be that when you declared a const variable the compiler would
- Allocate the space in ROM to hold the data
- And also allocate the space in RAM to hold a copy of the data, you would operate to the RAM copy
Yes, the compiler isn't free, it has a limit on how much ROM/RAM you can use in free mode. Now, i wonder why they decided to operate this way  ::)
Yes, if you tried to change the variable in C the compiler would throw an error. Never tried to debug to see if i could change it at runtime because i needed their debuggers, they didn't support the pickits at that time  :palm:
 

Online helius

  • Super Contributor
  • ***
  • Posts: 3800
  • Country: us
Re: constants Array scope in "C'"
« Reply #4 on: December 26, 2018, 10:09:45 pm »
I need to use a constant array, Since the array is accessed by several functions it ended up in global space.
What you're calling "global space" is formally known as top-level scope. This is a scope that is visible from the point of declaration to the end of the file. As mentioned above, const is a type qualifier and is not related to the scope in which an identifier is visible. const restricts what can be done to the object, not where it can be seen.

Along with scope is the issue of extent, the time during which the object is defined. Objects can have either local or static extent, which is related to the place they are allocated in memory. Local extent objects are called automatic and are allocated on the stack, in the current stack frame. Each time the block is executed, they are initialized in the top frame of the stack. When their enclosing block is exited, they are deallocated as the top frame of the stack is discarded. Static extent objects, by contrast, are allocated in a permanent location (called the Data segment) and remain there for the entire program execution. All top-level declarations have static extent, as do local (block) declarations with the static storage class specifier.

A different, related, issue is linker visibility. The object that you declare in top-level scope can be truly local to its own file, or made visible ("exported") to the linker so it can be seen in other files, as well. When the storage class static is used on the top-level declaration, it ensures that only its own file can see it. If static is not used, the storage class defaults to extern which is made visible to other files via the linker. The only way that extern is literally typed in is for declarations that refer to a definition in another file. So the three cases for linker visibility are:
  • nothing - external and defined by this file
  • extern - external and defined in another file
  • static - internal

Quote
Under what conditions should constants be declared in global space?
Constants should be defined with static extent, as that ensures they are initialized at load time only. Both top-level declarations, and local declarations with static have static extent. The choice depends on whether the object must be visible in more than one function's scope.

Quote
If the constant is declared  in main or in a function does it need to be declared as static?
See above—declaring an object as static ensures it has static extent.
 
Quote
Execution Speed is a concern, is there a benefit between  local vs global scope?
For maximum execution speed, compile with optimizations; this will often inline the constant values in the instructions so they do not require memory accesses. Memory for local vs global scope are accessed at the same speed on most machine architectures.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4666
  • Country: us
Re: constants Array scope in "C'"
« Reply #5 on: December 27, 2018, 03:30:31 am »
Quote
Fun fact, with the Mikro C compiler for microchip PIC it used to be that when you declared a const variable the compiler would
- Allocate the space in ROM to hold the data
- And also allocate the space in RAM to hold a copy of the data, you would operate to the RAM copy
Now, i wonder why they decided to operate this way
AVR compilers do the same thing.  It's pretty much REQUIRED by the Harvard Architecture used by those microcontrollers - code can not access ROM data in the same way that it accesses RAM data - it best, it takes different instructions, and you need two copies of functions like "strcpy(dst, src)" depending whether "src" is in RAM or ROM.  (also, you usually lack whatever fancy addressing modes might be available for RAM, when accessing the ROM...)
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3916
  • Country: it
Re: constants Array scope in "C'"
« Reply #6 on: December 27, 2018, 07:02:05 am »
Never really been a problem for PICs (modified harvard)
- Since at least the 16F84A you had a RETLW instruction. Microchip put code in the datasheet on how to make lookup tables with a branch to a relative address and a sequence of RETLWs. It gets more complicated with 16 bit, but it would be anyway because 8 bit core
- when they added self-programming you could also read the whole program word, so not only 8 bit but 14/16/24/32 depending on architecture with pre or post increment
- I think you can also use the indirect registers to point to flash in the latest PIC16/PIC18
- 16 bit parts can map the upper 32k of memory to blocks of flash memory or blocks of RAM. It only takes more cycles to access flash
- 32 bit parts have the address translator that points to flash or ram, whatever

PICs don't really need to copy ROM to RAM to make constants... devices with an handful of RAM but a shitload of flash can't have that luxury
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4666
  • Country: us
Re: constants Array scope in "C'"
« Reply #7 on: December 27, 2018, 09:56:34 am »
Quote
Never really been a problem for PICs (modified harvard)
- Since at least the 16F84A you had a RETLW instruction. Microchip put code in the datasheet on how to make lookup tables with a branch to a relative address and a sequence of RETLWs. It gets more complicated with 16 bit, but it would be anyway because 8 bit core
- when they added self-programming you could also read the whole program word, so not only 8 bit but 14/16/24/32 depending on architecture with pre or post increment
yeah, yeah.  You can read flash.  But NOT the same way you read data ram.  If you were writing strcpy(), you needed to know ahead of time which type of memory you were accessing.  You can't pass "&x" to a function and have it work regardless of whether x is in flash or RAM...


Quote
- I think you can also use the indirect registers to point to flash in the latest PIC16/PIC18
I don't think so.    Seems especially unlikely, with a 2Mb flash address space (on PIC18; 64k on PIC16, I think) and only 8k/4k of RAM and 16bit "indirect registers."
I can't comment on the 16bit PICs.PIC32 has the whole MIPS 32bit unified address space, so it doesn't have any problems with data in flash.  I'm pretty sure that "const" is all you need to put variables in flash, on PIC32.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3567
  • Country: ca
Re: constants Array scope in "C'"
« Reply #8 on: December 27, 2018, 10:27:26 pm »
yeah, yeah.  You can read flash.  But NOT the same way you read data ram.  If you were writing strcpy(), you needed to know ahead of time which type of memory you were accessing.  You can't pass "&x" to a function and have it work regardless of whether x is in flash or RAM...

The XC8 PIC compiler actually allows you to do this. You may have universal pointers which can point anywhere - the compiler furnish the correct function in all cases - even if it needs to select it at run-time.

On the other hand, PIC24/dsPIC33 have a feature called Program Space Visibility (PSV) which lets you map a selected part of the Code address space into the Data address space. This way you can access flash and RAM with the same strcpy(). Of course, you cannot write flash this way.
 

Offline gogomanTopic starter

  • Regular Contributor
  • *
  • Posts: 123
Re: constants Array scope in "C'"
« Reply #9 on: January 03, 2019, 02:50:59 pm »
"Along with scope is the issue of extent, the time during which the object is defined. Objects can have either local or static extent, which is related to the place they are allocated in memory. Local extent objects are called automatic and are allocated on the stack, in the current stack frame. Each time the block is executed, they are initialized in the top frame of the stack. When their enclosing block is exited, they are deallocated as the top frame of the stack is discarded. Static extent objects, by contrast, are allocated in a permanent location (called the Data segment) and remain there for the entire program execution. All top-level declarations have static extent, as do local (block) declarations with the static storage class specifier."

Hi, thanks you for all the replies a few more questions. forgive me if I'm being redundant 

if the object is used by other functions is there a reason not to declare the object in main as a static constant?
For functions which use this object is it standard practice to pass the object to the function using a pointer?

 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3567
  • Country: ca
Re: constants Array scope in "C'"
« Reply #10 on: January 03, 2019, 03:22:50 pm »
if the object is used by other functions is there a reason not to declare the object in main as a static constant?

There's no such thing as static constant in C. They're all variables. The variables declared with "const" cannot be changed by the programmer (that is they're read only), but it is possible for them to change due to external causes. The keyword which determines whether external forces can change your variable is "volatile".

The C compiler for MCUs often hijack the "const" keyword interpreting it as "located in flash". This is not standard in C and you must read the documentation for your particular compiler.

There are also constant expressions (whose result is known at compile time). Note they are expressions, not a variables. They aren't stored anywhere at run time, most likely get embedded in the code by the compiler.

For functions which use this object is it standard practice to pass the object to the function using a pointer?

Typical reasons why you would want to pass a pointer (as opposed to value) might be:

- the function may change the object being passed
- the size of the object may vary
- the object is too big to be passed directly

 

Offline BloodyCactus

  • Frequent Contributor
  • **
  • Posts: 484
  • Country: us
    • Kråketær
Re: constants Array scope in "C'"
« Reply #11 on: January 03, 2019, 06:15:23 pm »
'volatile' is more, dont cache this content. Since C is half pass by ref and half pass by val.  Say, using a value in an inner loop, each read of the variable in that tight loop wont be updated, but if volatile, it will be updated. (ie: clock ticks incremented in an isr).

const can be a pain, lots of old C code abused const, some compilers would be const data into the read only text segment, some i the data segment, I've seen lot of old C modify a string that one compiler had in data, another put in text and thus read only.

There's no such thing as static constant in C.

static is a storage class, so you can have a static const, static just means 'visible only within this file'. its about scope. a static const just makes that function or variable visibile to other functions within that same C file.
« Last Edit: January 03, 2019, 06:17:03 pm by BloodyCactus »
-- Aussie living in the USA --
 

Offline ggchab

  • Frequent Contributor
  • **
  • Posts: 292
  • Country: be
Re: constants Array scope in "C'"
« Reply #12 on: January 04, 2019, 12:34:45 pm »
Quote
Never really been a problem for PICs (modified harvard)
- Since at least the 16F84A you had a RETLW instruction. Microchip put code in the datasheet on how to make lookup tables with a branch to a relative address and a sequence of RETLWs. It gets more complicated with 16 bit, but it would be anyway because 8 bit core
- when they added self-programming you could also read the whole program word, so not only 8 bit but 14/16/24/32 depending on architecture with pre or post increment
yeah, yeah.  You can read flash.  But NOT the same way you read data ram.  If you were writing strcpy(), you needed to know ahead of time which type of memory you were accessing.  You can't pass "&x" to a function and have it work regardless of whether x is in flash or RAM...


Quote
- I think you can also use the indirect registers to point to flash in the latest PIC16/PIC18
I don't think so.    Seems especially unlikely, with a 2Mb flash address space (on PIC18; 64k on PIC16, I think) and only 8k/4k of RAM and 16bit "indirect registers."
I can't comment on the 16bit PICs.PIC32 has the whole MIPS 32bit unified address space, so it doesn't have any problems with data in flash.  I'm pretty sure that "const" is all you need to put variables in flash, on PIC32.

I am programming PIC24 and dsPIC33 and I think it's the role of the PSV window to give access to 32K of ROM as if it was RAM. I use "&x" to pass "const" (stored in flash) and "non const" variables to the same function.

On some PIC (at least 12F1822), FSR registers may be used to access the program flash memory.
 

Offline 0xdeadbeef

  • Super Contributor
  • ***
  • Posts: 1911
  • Country: de
Re: constants Array scope in "C'"
« Reply #13 on: January 04, 2019, 01:10:13 pm »
For the record: in the automotive world, the calibration data (calibration maps, constants etc.) is put in a const section and there are several approaches used to map this Flash/ROM section to RAM during development.
In former times with external ROM e.g. the uppermost address line was used to select an external RAM. With today's 32bit microcontrollers, usually the MMU is used to switch between internal Flash and external RAM. But there are some automotive microcontrollers like the Infineon Tricore/Aurix and the Renesas RH850 E2x which still don't support an MMU, so they have some special overlay registers to map internal RAM over Flash.
For the production devices, the internal RAM is not nearly sufficient to cover all the calibration data (multiple Megabytes nowadays), so there are some specific "emulation devices" which cost like 1k€ and have a few additional MB of embedded RAM to mirror the calibration ROM.
That's why embedded compilers used in the automotive world always have to include an option that forbids any optimization for const sections. Note in this context that usually you can't declare a variable const and volatile, as this doesn't any make sense in standard C. Most compilers should complain about this and static code checkers like PC-Lint should do so as well.
Trying is the first step towards failure - Homer J. Simpson
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3567
  • Country: ca
Re: constants Array scope in "C'"
« Reply #14 on: January 04, 2019, 03:27:17 pm »
Quote
- I think you can also use the indirect registers to point to flash in the latest PIC16/PIC18
I don't think so.    Seems especially unlikely, with a 2Mb flash address space (on PIC18; 64k on PIC16, I think) and only 8k/4k of RAM and 16bit "indirect registers."

XC8 compiler selects the size for the pointer. Different pointers may be of different size - from 1 to 3 bytes. XC8 analyzes what the pointer can point to and selects accordingly. They call it "omniscient code generation". It's a lot of work to make C concepts to work on PIC16/18.

If I remember correctly, the earlier compiler - C18, required you to specify where your pointer points to data or to flash. I would actually prefer this over what XC8 is doing.

I can't comment on the 16bit PICs.

XC16 and XC32 are different from XC8 and are GCC based.
 

Offline dmills

  • Super Contributor
  • ***
  • Posts: 2093
  • Country: gb
Re: constants Array scope in "C'"
« Reply #15 on: January 04, 2019, 08:15:44 pm »
Note in this context that usually you can't declare a variable const and volatile, as this doesn't any make sense in standard C.
Actually volatile const is a perfectly valid construct in embedded C.

volatile - value may be modified from outside the C execution context.
const - value cannot be modified from within the C execution context.

So something like a read only peripheral status register makes perfect sense as a pointer to a volatile const object.
 
Granted your MISRA tool will throw a fit, but that sort of low level driver stuff tends to need a set of documented exceptions anyway.

Regards, Dan.
 

Offline 0xdeadbeef

  • Super Contributor
  • ***
  • Posts: 1911
  • Country: de
Re: constants Array scope in "C'"
« Reply #16 on: January 04, 2019, 08:23:05 pm »
What I meant is that a variable can't be constant and volatile and the same time.
Const pointers are a special breed though. It matters a lot if the address is constant or the value the pointer points to. This is decided by the location of the const qualifier in the definition.
Most embedded developers aren't fully aware of that and just put the const somewhere which again lots of compilers still accept due to special settings for const handling. Still, combining const and volatile without knowing what you do can lead to extremely surprising results. Just had to deal with this end of last year.
Trying is the first step towards failure - Homer J. Simpson
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3958
  • Country: de
Re: constants Array scope in "C'"
« Reply #17 on: January 04, 2019, 08:28:25 pm »
AVR compilers do the same thing.  It's pretty much REQUIRED by the Harvard Architecture used by those microcontrollers - code can not access ROM data in the same way that it accesses RAM data - it best, it takes different instructions, and you need two copies of functions like "strcpy(dst, src)" depending whether "src" is in RAM or ROM.  (also, you usually lack whatever fancy addressing modes might be available for RAM, when accessing the ROM...)

Erm,  nope. If you want to put/access something in ROM (= Flash) on AVRs, you need to tag the pointer/variable using PROGMEM.

Declaring something const is not enough - and it makes no sense neither, because const only means that you can't change the value using that particular name. I.e. you can have a variable and two pointers at it, one const, one non const and it is completely legal C - you can freely change that value using the non const pointer and there is no problem (whether or not it is a good programming style is another discussion).  You can also cast the "constness" away and modify the value at will (again, let's not go into the issues of a good programming style). Again a completely legal operation (in fact, C++ has even a special cast operator just for this: const_cast).

All that would break if the compiler made assumptions about where to store the data. GCC is actually standard compliant compiler, unlike that Mikro C.

« Last Edit: January 04, 2019, 08:55:00 pm by janoc »
 

Offline charliex

  • Frequent Contributor
  • **
  • Posts: 346
  • Country: 00
  • Car Hacker
Re: constants Array scope in "C'"
« Reply #18 on: January 04, 2019, 08:33:15 pm »
a variable can be const and volatile at the same time, for instance a hardware clock/timer/counter, it just means it is read only and for the compiler to handle it properly, not that the value never changes. it doesn't need to be a pointer since you can specify where the variable exists with a linker script or extension.

 

Offline 0xdeadbeef

  • Super Contributor
  • ***
  • Posts: 1911
  • Country: de
Re: constants Array scope in "C'"
« Reply #19 on: January 04, 2019, 08:54:14 pm »
a variable can be const and volatile at the same time, for instance a hardware clock/timer/counter, it just means it is read only and for the compiler to handle it properly, not that the value never changes. it doesn't need to be a pointer since you can specify where the variable exists with a linker script or extension.
I'm not sure if your timer example is valid.

IMHO, standard C assumes a "const" variable to never alter its value during runtime. So it's not only "read only" but "constant" - hence the name.
Actually I would be surprised if you could define a const variable without assigning it a value. IMHO this is different to the similar qualifier "final" in Java which allows a single write access after the actual definition.
Plus I'm convinced that non-embedded C compilers will replace const variables with immediate values in higher optimization levels.

Anyway, I never saw an example of peripheral registers being mapped to the correct address through linker scripts. Actually several linkers/locators I worked with won't allow this for a specific variable but only for a section. So you'd need a section for each peripheral register which is somewhat nuts. Besides it would be just a linker trick and has nothing to do with C syntax. So the C compiler would still need the initialization value for your constant and write that over your read only timer one way or the other.
Trying is the first step towards failure - Homer J. Simpson
 

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1198
  • Country: fi
Re: constants Array scope in "C'"
« Reply #20 on: January 04, 2019, 09:02:30 pm »
I'm not sure if your timer example is valid.
It is straight from the C standard. §6.7.3, page 109 in the C99 TC3 final draft:
Quote
EXAMPLE 1 An object declared
Code: [Select]
extern const volatile int real_time_clock;may be modifiable by hardware, but cannot be assigned to, incremented, or decremented.

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3567
  • Country: ca
Re: constants Array scope in "C'"
« Reply #21 on: January 04, 2019, 09:33:28 pm »
IMHO, standard C assumes a "const" variable to never alter its value during runtime.

The whole point of the standard is to define things as clearly as possible, so it would be impossible to have an opinion which is different from what the standard describes.
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3958
  • Country: de
Re: constants Array scope in "C'"
« Reply #22 on: January 04, 2019, 10:14:49 pm »
IMHO, standard C assumes a "const" variable to never alter its value during runtime.

The whole point of the standard is to define things as clearly as possible, so it would be impossible to have an opinion which is different from what the standard describes.

The problem isn't the standard but the fact that many people who are arguing about it have never read it. The actual text costing about $30 isn't helping the situation.

And 0xdeadbeef's opinion is wrong, the standard doesn't "assume" anything such. Look for  yourself:

http://www.dii.uchile.cl/~daespino/files/Iso_C_1999_definition.pdf (p. 108, type qualifiers).

It just says that if you try to access a const qualified object using a non-const lvalue, the results are undefined (i.e. implementation dependent). It also says that an implementation may (but doesn't have to) place const but not volatile objects into read-only storage. And that's pretty much all that there is on const in the standard.

« Last Edit: January 04, 2019, 10:20:48 pm by janoc »
 

Online cv007

  • Super Contributor
  • ***
  • Posts: 1061
Re: constants Array scope in "C'"
« Reply #23 on: January 04, 2019, 10:46:23 pm »
One example of using 'const volatile' is if a flash constant is updated via a flash write (flash storage for settings when eeprom not available, for example)- you just told the compiler you can't write to it, but you better read it when we ask for its contents since it may have changed without your knowledge (from a flash write, which the compiler will not know about).
 

Offline 0xdeadbeef

  • Super Contributor
  • ***
  • Posts: 1911
  • Country: de
Re: constants Array scope in "C'"
« Reply #24 on: January 05, 2019, 12:22:54 am »
OK, you got me there. I guess we can agree though that the standard is (again) pretty vague here but I must admit I'm surprised that it really names the "const volatile" example.
I still think it's an obscure case and it would have been better to forbid it as there is no real use to something like this when you can as well use a const pointer.
Anyway, I would avoid something like this like the plague for portability and robustness.
E.g. I'm pretty sure though that the compiler I currently work with in our latest project throws a compiler error if you try to define something as volatile and const.
It also optimizes most volatile const pointers to registers by replacing them with immediate values.
Then again, it also complains about other things that I would assume to be correct (const pointer to const value).
Trying is the first step towards failure - Homer J. Simpson
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->