View previous topic :: View next topic |
Author |
Message |
silelis
Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district
|
How to pass const array to function |
Posted: Thu Oct 04, 2018 10:28 am |
|
|
Hello,
For some reason I have quite big char array that is not changing so I want them to be const array. But I have problem with passing it to function.
Normally if this array is variable it is possible to pass it to function as pointer.
Code: | v
//it compiles
oid function_with_const_array(int array_to_pass[])
{
int c;
c=array_to_pass[0]+1;
}
void main()
{
int array[2]={1,2};
function_with_const_array(array);
} |
but If I change it to const like below the compiler gives errors
Code: |
void function_with_const_array(const int array_to_pass[])
{
int c;
c=array_to_pass[0]+1;
}
void main()
{
const int array[2]={1,2};
function_with_const_array(array);
} |
It is obvious because there is no such thing like pointer to const but I wonder how to fix this issue. I mean to pass const array to function.
I know that I can declare const array in function body, but I will pass to this function 2 or more const arrays. Also I don't want to make variable because from my point of view it is waste both ram and rom space (as I said those are const's). I have considered to write const to variable (in function block) and pass it as variable to function but malloc, free and so on functions also take a huge amount of rom. So I am searching for simplest solution to pass array(s) to function. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Fri Oct 05, 2018 12:13 am |
|
|
Possibly
#device PASS_STRING=IN_RAM
The problem is because of the nature of the PIC processor. The PIC uses Harvard architecture, rather than the more normal Von Neumann architecture.
The Von Neumann architecture has a single adress space, and your ROM and RAM all appear in this single space. So address 0x1000 might be in ROM, and address 0x4000 in RAM. A single 'address' number can talk to anywhere in the memory. In the Harvard architecture, the ROM and RAM are in completely separate data spaces. There is an address 0x1000 in the ROM, and another address 0x1000 in the RAM. A RAM 'pointer' can't be constructed to talk to the ROM.
Now the compiler offers various ways of 'working round' this. Some depend on the processor involved. So:
First method.
char arrays, can be automatically 'virtualised'. The PASS_STRINGS option shown above, will automatically create a 'psuedo' pointer value, which then copies part of the const array into RAM, and allows it to be accessed as if it was in RAM. Uses a small RAM buffer to do this. Only works for text arrays.
Second ROM.
Declaring a constant using the rom keyword, instead of const, allows a rom pointer to be constructed:
Code: |
void function_with_const_array(rom int array_to_pass[])
{
int c;
c=array_to_pass[0]+1;
}
void main()
{
rom int array[2]={1,2};
function_with_const_array(array);
}
|
Using the rom keyword, the compiler adds code to generate pointers.
Third (DsPIC's only) PSV.
The DsPIC's have a feature that allows part of their ROM to be mapped into the RAM address space. Program Space Visibility. On these chips enabling the feature by adding #device PSV=16, will allow RAM pointers to access const/rom data directly through this feature.
Fourth sequential access.
The compiler has a feature that dates from the earliest PIC's where ROM could not actually be read. On these to generate a const array, a program had to be created that returned an addressed byte when called. Means you can access the array in a slightly different way:
Code: |
void function_with_const_array(int val)
{
int c;
c=val+1;
}
void main()
{
const int array[2]={1,2};
function_with_const_array(array);
}
|
Will actually result in 'function_with_const_array', being called twice, the first time with array[0], and the second with array[1]. What is done is the program to access the const is called with each possible index in turn, and the value returned is passed to the function. Allows a lot of code to be written without actually accessing the 'array' as such.
Probably for what you describe, the rom keyword is most likely to do what you want. |
|
|
silelis
Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district
|
|
Posted: Sat Oct 06, 2018 4:27 am |
|
|
I have decided to use second way. "rom char".
It did not work directly. To access rom data it is required to use read_program_eeprom.
The program looks like:
Code: | void function_with_const_array(int array_to_pass[])
{
char data = read_program_eeprom (array_to_pass);
fprintf(Dbg, "Value: %d \r\n", data);
data = read_program_eeprom (array_to_pass+1);
fprintf(Dbg, "Value: %d \r\n", data);
//fprintf(Dbg, "Value: %d \r\n", array_to_pass[0]);
}
void main()
{
rom int array[]={12,22};
//int *p;
//p=&array;
function_with_const_array(array);
} |
But it is working now and BIG THX for Your help. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Sat Oct 06, 2018 12:24 pm |
|
|
It should work directly with the address declared as rom *.
The only thing I did not try was passing this as an array declaration rather than a pointer declaration. The normal way to declare the function would be:
void function_with_const_array(rom int * array_to_pass)
Now in C an array declaration and a pointer are equivalent, so I expected the array declaration to work, however if it doesn't, it suggests CCS may not respect the equivalence in this specific case. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Sun Oct 07, 2018 2:10 am |
|
|
Yes. Just built a basic test program, and the compiler accepts rom *, but not building as an array. A bit naughty...
Code: |
#include <18F4520.h>
#device ADC=10
#FUSES NOWDT //No Watch Dog Timer
#use delay(crystal=20000000)
#use rs232(UART1, baud=9600, ERRORS)
int8 func_using_ptr(rom int8 * array)
{
//test array
int8 sum;
sum=array[0];
sum+=array[1];
return sum;
}
void main()
{
rom int8 test[]={1,2};
int8 sum;
while(TRUE)
{
sum = func_using_ptr(test);
printf("sum is %d\n", sum);
delay_ms(1000);
}
}
|
as you can see it makes no functional difference (you can still reference it as an array). |
|
|
silelis
Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district
|
|
Posted: Sun Oct 07, 2018 10:53 am |
|
|
I see. So I made something wrong. Once again thank You for Your time and for help. :-) |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Sun Oct 07, 2018 2:09 pm |
|
|
No, you didn't make a mistake.
In C a parameter passed to a function as [] is an equivalent alternative to passing as a pointer. The language should accept either. In the case of a rom pointer type, the language is not accepting this equivalence... |
|
|
silelis
Joined: 12 Jun 2007 Posts: 68 Location: Poland, podlaskie district
|
|
Posted: Tue Oct 09, 2018 10:00 am |
|
|
I have also question about "#device PASS_STRING=IN_RAM".
This pseudo pointer and virtual constant "is" during function execution only or during all program execution?
I mean if it use RAM temporary or permanently? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Tue Oct 09, 2018 10:38 am |
|
|
The amount it uses is tiny. I think it is typically perhaps 4 bytes!. It is global, so 'all the time'. |
|
|
|