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 CCS Technical Support

Array of pointers to strings

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



Joined: 01 Jun 2017
Posts: 2
Location: Sydney, Australia

View user's profile Send private message

Array of pointers to strings
PostPosted: Thu Jun 01, 2017 6:29 am     Reply with quote

I need to have an array of pointers to const strings so that I can output the appropriate message based on incoming data. Processor is PIC16F877A. Compiler version is v4.112

The normal C syntax of:
const char *strs[] = {"Str1", "Str2", ... "Strn"};

does not work at all. The compiler produces code that just cannot work.

Checking the manual I have found another 'special' syntax that is supposed to do the same thing:
const char strs[][*] = {"Str1", "Str2", ... "Strn"};

When I try to use this syntax i get the following errors:

Code:
Clean: Done.
Executing: "C:\Program files\Picc\CCSC.exe" +FM "main.c" +DF +LN +T +A +M +Z +Y=9 +EA
*** Error 27 "main.c" Line 4(23,24): Expression must evaluate to a constant
*** Error 43 "main.c" Line 4(25,26): Expecting a declaration
*** Error 43 "main.c" Line 4(27,28): Expecting a declaration
*** Error 43 "main.c" Line 4(33,34): Expecting a declaration
*** Error 43 "main.c" Line 4(33,34): Expecting a declaration
*** Error 43 "main.c" Line 4(42,43): Expecting a declaration
*** Error 43 "main.c" Line 4(42,43): Expecting a declaration
*** Error 43 "main.c" Line 4(50,51): Expecting a declaration
*** Error 43 "main.c" Line 4(50,51): Expecting a declaration
*** Error 43 "main.c" Line 4(51,52): Expecting a declaration
      10 Errors,  0 Warnings.
Halting build on first failure as requested.
BUILD FAILED: Thu Jun 01 22:02:44 2017


The source code for a simple test program that produced these errors is:
Code:

#include <main.h>
#include <string.h>

const char colors[] [*] = {"Red", "Green", "Blue"};

char   obuf[10];

void main()
   {
   int      i;
   
   for(;;) {
      for(i = 0; i < 3; i++)
         sprintf(obuf, "%s", colors[i]);
      }
   }
   

I have wasted most of a day on this and am getting rather p'd off
Mad

I would be eternally grateful if anyone can suggest how this can be done.

TIA
Gerry
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Thu Jun 01, 2017 6:41 am     Reply with quote

look for the following in the ccs manual

Quote:
A (non-standard) feature has been added to the compiler to help get around the problems
created by the fact that pointers cannot be created to constant strings.


and have a read about syntax etc in CCS
and BTW : welcome to the rodeo
temtronic



Joined: 01 Jul 2010
Posts: 9245
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Jun 01, 2017 7:04 am     Reply with quote

re:...
The normal C syntax...

There is no such things as 'normal' for C or anything else these days..
Even ANSI C has 'variants'....

You need to understand that PICs were not designed for 'normal' C, rather they were Peripheral Interface Controllers, originally programmed in Assembler( 35 instructions...child's play to learn ) . As they evolved, so did the languages programmers could use... Interpreter BASIC, Compiled BASIC and at least 3 or 4 versions of 'C'.

We see postings here all the time that code cut in other Cs doesn't work as CCS C. You need to translate into CCS style C. What others do in 10-12 lines of code, CCS does it in 1 making code cutting easy and fun,especilay for us older guys who grew up on Assembler. My first version of CCS C was 2.4xx BTW.

Their manual and examples are a 'must' read to understand how CCS implements 'C'.

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Thu Jun 01, 2017 7:50 am     Reply with quote

The const char strs[][*] = {"Str1", "Str2", ... "Strn"};
syntax, was not available in 4.112. You are reading a manual for a later compiler (actually, 'thinking about it', this was about when it was announced, but it didn't work till later).

------- updated
Thinking about this again, the feature was there to support variable length strings, but _not_ to construct pointers to them.
So you could access a string using array indexes, but not pass the address as a pointer to a function. The only methos that supported pointers to ROM in this old compiler, was the rom form.
-------- updated

A search here will find lots of posts explaining the fundamental difficulty here. The PIC uses a Harvard architecture, not a Von Neumann architecture. This means there are two _separate_ memory spaces, instead of one linear space. So there is an 'address 0' in ROM, and another 'address 0' in RAM. Two different locations for the same pointer....

Later compilers also allow an option PASS_STRINGS=IN_RAM, which will automatically 'virtualise' string accesses to the ROM.

Even worse though a lot of the older chips don't actually allow the ROM memory to physically be read. So data stored in the ROM has to be stored as a program subroutine, that returns the value required. Imagine trying to construct a 'pointer' to data from this!... Sad
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 01, 2017 11:44 am     Reply with quote

I installed vs. 4.112 and tried to get something that would work.
The program shown below is the best you can do with that version.
When I ran it in MPLAB vs. 8.92 simulator, I got the following output:
Quote:

Red
Green
Blue

Compiler vs. 4.112 does support #device PASS_STRINGS=IN_RAM,
but it's not necessary for this program.

Test program:
Code:

#include <16F877A.h>
//#device PASS_STRINGS=IN_RAM
#fuses XT, NOWDT, BROWNOUT, NOLVP
#use delay(clock=4M)
#use rs232 (baud=9600, UART1, ERRORS)

#include <string.h>

char const colors[3][6] = {"Red", "Green", "Blue"};

char   obuf[10];

//=============================
void main()
{
int i;
   
for(i = 0; i < 3; i++)
   {
    sprintf(obuf, "%s", colors[i]);
    printf("%s \r", obuf);
   }

while(TRUE);
}


Vs. 4.112 came out around August 29, 2010.
The closest manual I can find to that date is the June 2010 manual:
http://svn.modlabupenn.org/mod-ros-pkg/CKBot/branches/pyckbot/mcu/ckbot-HAL/hal/pic18-ccs/ccs_c_manual.pdf
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Thu Jun 01, 2017 1:31 pm     Reply with quote

PCM, I was guessing that the 'demo', was not his real use, and he wants to pass a pointer to an element in the array to a function.
I have notes in my code that PASS_STRINGS, was unreliable in the versions round here, and only started working properly around .130. So 'late' V4, and V5 only. It would allow what I was assuming he wanted, if it does work.

It's perhaps worth pointing out, that even on the versions before this works, you can de-reference the const into RAM yourself, so instead of passing the pointer, just copy the required string to RAM, and access this one array in the function.
MarkchchPIC



Joined: 14 Jan 2015
Posts: 18
Location: Christchurch New Zealand

View user's profile Send private message

One Suggestion
PostPosted: Thu Jun 01, 2017 3:08 pm     Reply with quote

Hi There,

I did a similar thing using the following code.
I created the array of "messages" as const to keep it in ROM.
Code:

char CONST message[21][17]=
{
   "READY....       ", //0
   "PLEASE WAIT...  ", //1
   "SYSTEM OK       ", //2
   "SYSTEM BOOT     ", //3
   "PIC CONTROLLER  ", //4
   "COMMAND         ", //5
   "CMD INVOKED     ", //6
   "choose M E N U  ", //7
   "SUPPLY VOLTS    ", //8
   "SETTING COUNT   ", //9
   "SETTING RTC...  ", //10
   "Select:         ", //11
   "NO DATA         ", //12
   "CHANNEL 1       ", //13
   "CHANNEL 2       ", //14
   "SET MAX         ", //15
   "SET MIN         ", //16
   "STEPPER SET     ", //17
   "CURRENT TEMP    ", //18
   "SAVING DATA     ", //19
   "SAVING TIME     ", //20
};

Then called a message to my LCD using the Flex Driver with this:
Code:

void messageLCD(int16 mess,INT8 line,int8 pos)
{
   lcd_gotoxy (pos, line) ;
   printf (lcd_putc,"%s",message[mess]);
}


Not sure if this helps or if I have posted the code correctly.

Cheers

Mark
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 01, 2017 9:37 pm     Reply with quote

Ttelmah wrote:

PCM, I was guessing that the 'demo', was not his real use, and he wants
to pass a pointer to an element in the array to a function.
I have notes in my code that PASS_STRINGS, was unreliable in the
versions round here.

I did test that with vs. 4.112, and it works in the program shown below.
I didn't post it, but I'll do that now. The program below displays the
following output in MPLAB vs. 8.92 simulator:
Quote:
Hello
World

Test program:
Code:

#include <16F877A.h>
#device PASS_STRINGS=IN_RAM
#fuses XT, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

int8 const world_array[] = "World";

void my_func(char *str)
{
printf(str);
putc('\r');
}

//============================
void main()
{

my_func("Hello");
my_func(world_array);

while(TRUE);
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Fri Jun 02, 2017 1:25 am     Reply with quote

Agreed. However that is not the double reference (so 2 dimensional array).

The double reference is only supported with fixed size elements as your first example uses. Obviously makes little difference if the elements are similar in size, but where you have a few elements only a few bytes long, and others that are large, it is a big saving.

So on a modern compiler:
Code:

#include <16F877A.h>
#device PASS_STRINGS=IN_RAM
#fuses XT, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

int8 const *world_array[] = {"World","Mars","Venus","Jupiter"};

void my_func(char *str)
{
   printf(str);
   putc('\r');
}

//============================
void main()
{
  int8 n;
  for (n=0;n<4;n++)
  {
     my_func("Hello");
     my_func(world_array[n]);
  }

  while(TRUE);



Will compile and run correctly, with the compiler generating RAM accesses to a ROM array of pointers.
Without pass_strings, this will fail on any compiler, because of the attempt to pass a pointer to a constant.

However on this earlier compiler, even with 'PASS_STRINGS', this will not compile. On this compiler, 'PASS_STRINGS' only worked for the simple access of passing a basic element into code that required a pointer. The '*' syntax intermittently worked on some V4 compilers, (and never seemed to work without a number of elements definition for the first element), but though it is listed in the manual, largely stopped working when PASS_STRINGS was got fully working to handle an array as shown. At the time of this compiler, I don't think it worked at all.

So on his compiler, the * syntax doesn't work, and PASS_STRINGS won't allow an array of pointers. If what he was trying to do, was save space with mixed size elements, then I'm afraid that with such an old compiler, he is stuck. You can use the ROM for a fixed size array as you show, which may be acceptable, but doesn't quite 'do' the original requirement. Smile
gerryinaus



Joined: 01 Jun 2017
Posts: 2
Location: Sydney, Australia

View user's profile Send private message

Problem solved
PostPosted: Mon Jun 05, 2017 6:27 pm     Reply with quote

Hi everyone.
Thanks for your responses. I really appreciate it.

I have used the suggestion from 'PCM Programmer' and it is working like a charm. Although a little more expensive in terms of RAM usage it has delivered the desired result.
Job is complete and I have a satisfied client.

I had no choice but to use a PIC on this project but my personal preference for very small embedded applications is the Atmel ATmega series. They are very comparable on a cost basis but much more friendly from a code development perspective.

I believe that we can call this thread closed.

Thanks again.

Regards,

Gerry
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