CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

const not qualifier for a structure member

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
rikotech8



Joined: 10 Dec 2011
Posts: 376
Location: Sofiq,Bulgariq

View user's profile Send private message

const not qualifier for a structure member
PostPosted: Sun Jan 10, 2016 8:27 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jan 10, 2016 9:08 am     Reply with quote

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: 19278

View user's profile Send private message

PostPosted: Sun Jan 10, 2016 9:57 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jan 10, 2016 10:13 am     Reply with quote

Thank you PCM for the fast reply.
My intention is to place the string into the flash memory, not in ram. When I use
Code:
rom uint8_t *name
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

View user's profile Send private message

PostPosted: Sun Jan 10, 2016 11:07 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jan 10, 2016 11:28 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jan 10, 2016 10:51 pm     Reply with quote

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: 19278

View user's profile Send private message

PostPosted: Mon Jan 11, 2016 1:42 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jan 13, 2016 1:40 pm     Reply with quote

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: 19278

View user's profile Send private message

PostPosted: Wed Jan 13, 2016 3:55 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Jan 16, 2016 9:13 am     Reply with quote

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: 19278

View user's profile Send private message

PostPosted: Sat Jan 16, 2016 2:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jan 17, 2016 4:36 am     Reply with quote

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: 19278

View user's profile Send private message

PostPosted: Sun Jan 17, 2016 8:08 am     Reply with quote

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).
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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