|
|
View previous topic :: View next topic |
Author |
Message |
rikotech8
Joined: 10 Dec 2011 Posts: 376 Location: Sofiq,Bulgariq
|
const not qualifier for a structure member |
Posted: Sun Jan 10, 2016 8:27 am |
|
|
Hi,
Compiler 5.051.
I get error with this declaration:
Code: | typedef struct process_data
{
const uint8_t * name;
func_type func;
}process_data_t; |
This way, error is gone:
Code: | typedef struct process_data
{
uint8_t * name;
func_type func;
}process_data_t; |
Some ideas? _________________ A person who never made a mistake never tried anything new. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jan 10, 2016 9:08 am |
|
|
What is your intention ? The traditional CCS use of 'const' means to put
the value in ROM (in flash memory). But the ANSI C meaning of 'const'
means to store it in RAM, but treat it as read-only.
So what do you want ? The CCS meaning of 'const', or the ANSI meaning ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Sun Jan 10, 2016 9:57 am |
|
|
PCM makes an important distinction.
With the CCS usage, you are asking for a variable to be half stored in ROM, and half stored in RAM. This is basically not possible..... |
|
|
rikotech8
Joined: 10 Dec 2011 Posts: 376 Location: Sofiq,Bulgariq
|
|
Posted: Sun Jan 10, 2016 10:13 am |
|
|
Thank you PCM for the fast reply.
My intention is to place the string into the flash memory, not in ram. When I use I can see that RAM is much less. The intention to use const instead of rom qualifier is to make the code as portable, not only among different platforms, but different compilers too (if possible). I know I can use 'flags' and conditional compilation, but I am curious about this:
Quote: | typedef const uint8_t * cp; | is absolutely legal C declaration, but CCS doesn't accept that. _________________ A person who never made a mistake never tried anything new. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jan 10, 2016 11:07 am |
|
|
Quote: | My intention is to place the string into the flash memory, not in ram |
Just to be very clear for you, this is not a C concept. The C language
itself doesn't even know what ROM (or Flash Memory) is. As far as C
is concerned, it's all RAM. Anything else is an extension of the C
language, in this case by the CCS company. |
|
|
rikotech8
Joined: 10 Dec 2011 Posts: 376 Location: Sofiq,Bulgariq
|
|
Posted: Sun Jan 10, 2016 11:28 am |
|
|
OK I admit my question is vague.
I agree that (by standard) const has nothing to do with where the data resides in. I just protects the data from being modified, nothing more.
Please forget about my original post and let me try again.
Why CCS compiler version 5.051 doesn't like this type of declaration:
Code: | typedef const uint8_t * pointer_to_const_octet; | ???
Again thank you for replies. _________________ A person who never made a mistake never tried anything new. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jan 10, 2016 10:51 pm |
|
|
Below, you are creating a pointer that is stored in Flash Memory, but that
points to a ram location.
Code: | const uint8_t * pointer_to_const_octet; |
Because the address of the ram location is stored in Flash memory,
it can't be initialized at run time. Or at least, CCS doesn't permit this.
It must be initialized at compile time. If you don't do this, CCS will give
you an "Expecting an =" error message.
To fix this error, you have to add the part shown in bold below:
Quote: | int8 data;
const uint8_t * pointer_to_const_octet = &data;
|
But then, you tried to create a "pointer stored in Flash Memory" type, by
using 'typedef' and the compiler won't let you. It gives an "Expecting a ;
or ," error message.
I don't really know why. Possibly because of the requirement for
compile-time initialization. My advice is, don't use 'const'. Just store
the pointer in RAM. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Mon Jan 11, 2016 1:42 am |
|
|
rikotech8 wrote: | OK I admit my question is vague.
I agree that (by standard) const has nothing to do with where the data resides in. I just protects the data from being modified, nothing more.
Please forget about my original post and let me try again.
Why CCS compiler version 5.051 doesn't like this type of declaration:
Code: | typedef const uint8_t * pointer_to_const_octet; | ???
Again thank you for replies. |
You are fractionally missing the point.
Quote: |
"I agree that (by standard) const has nothing to do with where the data resides in. I just protects the data from being modified, nothing more."
|
This depends on _what standard_ you are using.
CCS, had a 'const' type, before ANSI came along. In CCS's standard, 'const' implies storage in ROM. Problem is then that the variable is stored in a different data space, so a simple pointer cannot be constructed.
Your original code will compile, if you switch to using ANSI mode.
#DEVICE ANSI
This (amongst other things) switches the definition of 'const' to be to simply be a RAM variable that is (if possible) write protected. Note the 'if possible'. On the PIC it can't be write protected (there is no memory management to do this - the compiler will stop 'simple' writes from accessing it, but anything like a pointer write will be able to access it.....).
So creating an ANSI 'const' pointer like this, brings with it almost no advantage over just storing the pointer in RAM.
This was why PCM programmer asked right at the start, what your intention was?.
ANSI C, allows the pointer to be constructed (assuming it to be to RAM), but has no commands or ability to then specify the string to be stored in flash memory.....
This is why CCS added the 'rom' construct, which then allows a pointer to be _specified_ as being to ROM and constructed as such, and the separate 'rom' declaration to allow a variable to be placed in the flash memory.
In most chips, you can use a const * (RAM ) pointer to then talk to flash, since they have 'single address space', with ROM and RAM just being at different addresses in a linear address space. The PIC does not have this. The ROM and RAM are separate, so there is an address '0' in ROM, and a separate address '0' in RAM. This is what allows the PIC to be quite fast without having to use cache (a single instruction can simultaneously access ROM and RAM), but brings with it the need to handle two distinct address spaces, which is not something contained in any of the C 'standards'.... |
|
|
rikotech8
Joined: 10 Dec 2011 Posts: 376 Location: Sofiq,Bulgariq
|
|
Posted: Wed Jan 13, 2016 1:40 pm |
|
|
Ok, thank you for the comprehensive explanation. Now I face another problem.
This:
Code: |
typedef rom struct process_data
{
uint8_t * name;
void (*p_func)(void);
}process_data_t;
process_data_t processes = {15,16};
|
Is different from this:
Code: |
typedef struct process_data
{
uint8_t * name;
void (*p_func)(void);
}process_data_t;
rom process_data_t processes = {15,16}; |
The second excerpt places the data in flash. The first one copies it into RAM.
To me, both code snippets ought be equivalent. Although the compiler statistics show the opposite. _________________ A person who never made a mistake never tried anything new. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Wed Jan 13, 2016 3:55 pm |
|
|
rom is a specifically 'per variable' declaration. It doesn't propagate through a type. It should be documented and isn't), but this has been observed and reported here before. |
|
|
rikotech8
Joined: 10 Dec 2011 Posts: 376 Location: Sofiq,Bulgariq
|
|
Posted: Sat Jan 16, 2016 9:13 am |
|
|
Quote: | This is why CCS added the 'rom' construct, which then allows a pointer to be _specified_ as being to ROM and constructed as such, and the separate 'rom' declaration to allow a variable to be placed in the flash memory. |
It seems to me that pointers must always be in ram, no matter where they do point to. Otherwise they don't work. Consider this example:
Code: |
void ChipInit(void);
typedef void(*ft)(void);
typedef struct str
{
ft func;
}str_t;
rom str_t str = {&ChipInit};
//in main()
str.func(); // This line gives the error.
|
The error is Quote: | *** Error 53 "main.c" Line 30(8,12): Expecting function name
|
Or this one:
Code: |
typedef struct str
{
int* p_i;
}str_t;
int a,b;
rom str_t str = {&a};
//In main
fprintf(DEBUG_STREAM, "a = %u\n",str.p_i;); |
For this example, error is given as follows:
Quote: | *** Error 114 "main.c" Line 61(42,45): Printf format type is invalid ::
| I really get messed up with this `rom` construct. If CCS implies that `const` is notation that tells the compiler that data is to be stored in flash, then why don't they use Code: | const int * pointer2int; | to tell the compiler this points to flash area? _________________ A person who never made a mistake never tried anything new. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Sat Jan 16, 2016 2:46 pm |
|
|
No. In your first example, you have not declared the function. You only have a prototype, not the actual function, so the compiler cannot solve what the value that needs to be stored actually 'is'.
In the second, p_i is a _pointer_ to an integer, not an integer itself. Hence the wrong type.
Extended here:
On the 'const' question. The point is that older chips have no ability to construct a pointer to the ROM. Most of the first few thousand PIC types, could not access their own ROM. CCS used 'const' to instead build a program that returned a value from ROM, to allow variables to be stored there, but with the 'caveat' that pointers could not be constructed/used to this memory.
Later chips added the ability to read this memory, and so a second construct was created 'rom' which carried the ability to construct a pointer to the values.
Then ANSI came along with their use of 'const' to only imply a variable that was in some way 'protected', not stored in ROM. Now the PIC can't actually do this (it's really for chips with hardware memory management), but if ANSI mode is selected, the compiler will prevent direct 'write' operations to such a variable (though it can't prevent pointer based writes without every pointer operation having significant code added to check the range of the values involved...).
At about the same time, they added the ability to use an 'extended RAM' pointer, using a flag value outside the RAM address range, to access a value in ROM, by copying them to a temporary buffer. This is triggered by 'PASS_STRINGS=IN_RAM'.
The key thing is that the const construct in it's original form was a quick way to allow chips that could not access their ROM, to store constant values in the ROM memory. A 'bodge' to give a work-round for a chip hardware limitation. Then CCS have produced a total of about a dozen other work-rounds to allow the memory to be used in different ways. However it is vital to understand that these are never going to be 'standard'. You are dealing with hardware features. It's like expecting all UART's to behave the same. Of course they won't. The PIC has an unusual memory architecture, that restricts it's usability for some things (for instance you would not want to use a PIC for handling a large graphic display, where a chip that supported mapping the display RAM directly into the standard RAM address range would be far easier and better), but brings with it the advantage of allowing multiple memory accesses 'at once' to the separate spaces. Using ANSI mode, the compiler can be told to largely behave as if the chip had a linear single address range. If you want to program stuff into ROM directly, then _you_ have to do it by one of the non standard methods. Even on a PC, if you wanted to do this, you would have to write custom code using #ORG to locate the values into ROM. It is a machine specific thing.
You can write completely 'universal' code to do things like add two numbers, but when dealing with hardware there has to be customisation for this.
Use of different memory storage types, is specifically in the C89/90 list of exemptions. |
|
|
rikotech8
Joined: 10 Dec 2011 Posts: 376 Location: Sofiq,Bulgariq
|
|
Posted: Sun Jan 17, 2016 4:36 am |
|
|
Thank you @Ttelmah for the comprehensive explanation.
I tried different approach:
Code: |
typedef struct str
{
int* p_i;
}str_t;
int a;
rom str_t str = {&a};
//in main()
fprintf(DEBUG_STREAM, "a = %u\n", *str.p_i);
|
Please note the asterisk before the fprintf last argument.
Same error reported:
Quote: | *** Error 114 "main.c" Line 61(43,46): Printf format type is invalid ::
|
Same thing with the function pointer:
Code: |
void ChipInit(void)
{
//function definition body here
}
typedef void(*ft)(void);
typedef struct str
{
ft func;
}str_t;
rom str_t str = {&ChipInit};
//in main()
str.func(); //error refers to this line
|
The error reported:
Quote: |
*** Error 53 "main.c" Line 62(5,9): Expecting function name
|
_________________ A person who never made a mistake never tried anything new. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Sun Jan 17, 2016 8:08 am |
|
|
As you have been told several times. "rom *", is not the same type as "*". p_i is a RAM pointer, not a ROM pointer. Declaring str to itself be in ROM, does not change the type of the pointer contained _in_ the variable.
You can have the compiler generate an automatic 'virtual' pointer to ROM, by using #device PASS_STRINGS=IN_RAM, then using 'const'. The compiler will then generate a pointer to RAM which can be used to access the ROM (though at a cost in speed). |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|