Author Topic: text / strings in C  (Read 9877 times)

0 Members and 1 Guest are viewing this topic.

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
text / strings in C
« on: March 14, 2020, 06:58:03 pm »
I am looking to send data from a micro-controller to an LCD over SPI. Looking for discussions online yields nothing about this generically other than issues with getting the protocol to work at all.

What i am wondering is the mechanics of doing the code to accomplish this. I read that strings are not actually a thing in C. So does this mean that I create all "text" as arrays of characters and either tell my transmission function how many characters there are to cycle through or put some sort of end code in like the NUL that would be on a string and when i detect that character stop transmission.

I expect that if i were to use a string i would then have to use a pointer to move through the string so in effect may as well use an array as i can "address" each character more easily.

I am using GCC for ARM
 

Offline rhodges

  • Frequent Contributor
  • **
  • Posts: 306
  • Country: us
  • Available for embedded projects.
    • My public libraries, code samples, and projects for STM8.
Re: text / strings in C
« Reply #1 on: March 14, 2020, 07:10:02 pm »
I think it is easiest to terminate the characters with a zero (NUL) byte. When you use a string like "hello", the compiler will add the zero at the end for you.

Here is a snippet from my LCD library:
void lcd_puts(char *s)
{
    while (1) {
        if (*s == 0)
            return;
        lcd_putc(*s);
        s++;
    }
}

And you could do something like this:
{
    lcd_puts("Hello, world\r\n");
}
 
Currently developing STM8 and STM32. Past includes 6809, Z80, 8086, PIC, MIPS, PNX1302, and some 8748 and 6805. Check out my public code on github. https://github.com/unfrozen
 

Offline greenpossum

  • Frequent Contributor
  • **
  • Posts: 408
  • Country: au
Re: text / strings in C
« Reply #2 on: March 14, 2020, 07:41:33 pm »
I read that strings are not actually a thing in C. So does this mean that I create all "text" as arrays of characters and either tell my transmission function how many characters there are to cycle through or put some sort of end code in like the NUL that would be on a string and when i detect that character stop transmission.

I don't know what you think a string needs to be to be a thing in C. Certainly all the literature talks about strings and string functions.

When you write "hello" in a C program, the compiler treats this as an array with the characters h e l l o plus a NUL byte. All the string functions expect this NUL byte. Therefore if you write a function to output to a LCD you can stop on that NUL byte.

Here are some initialisation idioms and what they will create:

char string[] = "hello";  // string is a 6 char array with NUL as the last byte
char *string = "hello"; // string is a pointer to an anonymous 6 char array with NUL as the last byte
char string[6] = "hello";  // same as 1st case
char string[5] = "hello";  // legal, the NUL byte is omitted (this feature added to classic C for usage that didn't want to waste the last byte)

printf("Hello world\n"); // the function printf is handed the address of an anonymous 13 char array containing hello SP world NL NUL
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4078
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: text / strings in C
« Reply #3 on: March 14, 2020, 07:59:44 pm »
Code: (dirty example) [Select]
typedef struct {
    size_t len;
    char *string;
} string;

int string_create(string &this){
    this.len = 0;
    this.string = NULL;
}

int string_set(string &this, const char *s){
    if(this.string){
       this.len = strlen(s);
       void *t = malloc(this.len);
       strcpy(t, s);
       free(this.string);
       this.string = t;
   }else{
       this.len = strlen(s);
       this.string = malloc(this.len);
       strcpy(this.string, s);
   }
}
Now strings are a thing in C!
You get the idea. C doesn't have data containers. C only has pointers to data. The rest is up to your imagination.
As programmers without containers we have settled on a standard that representations of printable text in memory are terminated with a NUL,\0,0x00 character. So this is what the compiler does.
Your protocol may utilize more of the ascii set though. If you're transmitting printable text you may as well use those.

You may be able to use a string library if that makes you feel more comfortable:
https://github.com/kozross/awesome-c#string-manipulation

Quote
I expect that if i were to use a string i would then have to use a pointer to move through the string so in effect may as well use an array as i can "address" each character more easily.
[a] just means (+ (a * sizeof(type)) on a pointer.
« Last Edit: March 15, 2020, 01:48:25 pm by Jeroen3 »
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: text / strings in C
« Reply #4 on: March 14, 2020, 08:05:40 pm »
so long as throwing a string at something is fine for the compiler it's fine by me. So i can use a string and then need to use pointers to address the bytes or if I use

char string[] = "hello";  // string is a 6 char array with NUL as the last byte

I can just index through until i find a null character
 

Offline Yansi

  • Super Contributor
  • ***
  • Posts: 3893
  • Country: 00
  • STM32, STM8, AVR, 8051
Re: text / strings in C
« Reply #5 on: March 14, 2020, 08:19:01 pm »
Indexing through is the wrong approach (resulting in a slow code most cases).

Use pointer and post increment it. Whats so difficult?

I think it is easiest to terminate the characters with a zero (NUL) byte. When you use a string like "hello", the compiler will add the zero at the end for you.

Here is a snippet from my LCD library:
void lcd_puts(char *s)
{
    while (1) {
        if (*s == 0)
            return;
        lcd_putc(*s);
        s++;
    }
}

Polishing the example from rhodges a bit:

Code: [Select]
void lcd_puts(char *s)
{
    while (*s) {
        lcd_putc(*s++);
    }
}
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: text / strings in C
« Reply #6 on: March 14, 2020, 08:55:35 pm »
Aren't incrementing an index and incrementing a pointer the same effort? Your cleaned up code will go on forever as there is nothing to stop it at the end of the string so it will just run through the entire memory shoving random stuff onto the SPI.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: text / strings in C
« Reply #7 on: March 14, 2020, 08:58:00 pm »
OK I see it but is 0 the nul code?
 

Offline greenpossum

  • Frequent Contributor
  • **
  • Posts: 408
  • Country: au
Re: text / strings in C
« Reply #8 on: March 14, 2020, 09:06:37 pm »
Indexing into an array is more expensive than dereferencing a pointer, because of the addition of the index to the base address, although a smart compiler could reduce the disadvantage.

Yes NUL is the zero byte.
 

Offline dmills

  • Super Contributor
  • ***
  • Posts: 2093
  • Country: gb
Re: text / strings in C
« Reply #9 on: March 14, 2020, 10:10:41 pm »
Code: [Select]

int string_create(string &this){
    this.len = 0;
    this.string = NULL;
}
Pretty sure that ain't C.

Looks like C++ (Which has references) not C, but if you are going for C++, just skin it with std::string, possibly with a custom allocator, why reinvent the wheel, it is not like C++ does not already have 57 different varieties of kitchen sink built right in.
 

Offline rhodges

  • Frequent Contributor
  • **
  • Posts: 306
  • Country: us
  • Available for embedded projects.
    • My public libraries, code samples, and projects for STM8.
Re: text / strings in C
« Reply #10 on: March 14, 2020, 11:28:15 pm »
Your cleaned up code will go on forever as there is nothing to stop it at the end of the string ...
The final zero byte will evaluate as false and terminate the loop. No problem.

Yansi's code is exactly the same as mine, and most experienced C programmers will prefer that style. My code is expanded to make it easy for anyone to understand it perfectly. I am sure the compiler output will be exactly the same.
Currently developing STM8 and STM32. Past includes 6809, Z80, 8086, PIC, MIPS, PNX1302, and some 8748 and 6805. Check out my public code on github. https://github.com/unfrozen
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4026
  • Country: nz
Re: text / strings in C
« Reply #11 on: March 15, 2020, 02:08:59 am »
Indexing into an array is more expensive than dereferencing a pointer, because of the addition of the index to the base address, although a smart compiler could reduce the disadvantage.

Yes NUL is the zero byte.

It's exactly the same with any decent compiler e.g. gcc or LLVM.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14436
  • Country: fr
Re: text / strings in C
« Reply #12 on: March 15, 2020, 02:26:14 am »
Indexing into an array is more expensive than dereferencing a pointer, because of the addition of the index to the base address

Although it was true for pretty old architectures (or more recent but limited 8-bitters) in the general case, it's certainly not for most modern targets. Indexing comes at no cost as most modern ISAs have memory access instructions with base and offset. If anything, depending on the ISA, that could cost an extra register though, but only that. And if the indexing is linear in a loop, the compiler will select whatever is most efficient between that and just incrementing the base address register anyway. Either way, it's just incrementing a register, same cost.

 

Offline greenpossum

  • Frequent Contributor
  • **
  • Posts: 408
  • Country: au
Re: text / strings in C
« Reply #13 on: March 15, 2020, 02:41:44 am »
Of course I know that decent compilers will do the right thing but pointer manipulation is part and parcel of C(++) so no need to stick to Pascal habits. :P

References are not part of C, this to the other poster.
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21651
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: text / strings in C
« Reply #14 on: March 15, 2020, 03:10:25 am »
You may find it's better to add more functionality.  Reasons include non-blocking functions, shared use (i.e., from many functions, .c files), standardizing interface (could map it to stdout for example), etc.

For example, writing a string to the display could take up whole milliseconds at a time, precious time that might need to be spent polling devices or responding to interrupts.  Not that the write function would be interrupt-blocking, but it has to be if you want to get debug output from interrupt sources...

If it's buffered, like stdout, you don't have to worry about where or when data is sent.  As long as the buffer is updated atomically (usually by disabling interrupts, so it should be done quickly, too), it can receive data from any source (main or interrupt).

Downside is the buffer can fill up, so you do need to add checks for that.  Much better than completely missing a critical operation though.

Last time I did a HD44780 display, I used a buffer with in-band signaling.  Think it was that chars 0-7 were taken over for special functions (locate cursor, clear screen, etc.), and the rest are normal, like 8-15 are the programmable ones (CRAM) which are mirrored in that range so there's no loss of functionality, and 32-255 are normal.

Forget what string format I used on that project... it was a while ago.  I prefer to avoid ASCIIZ strings, the downside is fixed-length strings have to be passed by two parameters at all times (pointer and length), and the length is limited (whatever fits in a, char, short, whatever).

Of course if you're doing simple sequential stuff, basically doing Arduino stuff, blocking write functions are perfectly fine, too.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8167
  • Country: fi
Re: text / strings in C
« Reply #15 on: March 15, 2020, 08:15:00 am »
Of course strings are a thing in C. C strings are series of bytes in memory, terminated with value 0. (I like to say 0 when I mean 0, instead of some possibly confusing special names like nul or NULL depending on context. Of course, be careful not to confuse the ASCII character 0 to the actual digital value 0.) A string literal "A" differs from the character literal 'A' by the fact that compiler generates the terminating byte: "A" is {65, 0} in memory.

It's easy to understand why the C designers made such choice: it's freaking simple, and easy. It's so simple that apparently people think it's not "a thing" because it's too simple.

There are other ways to do it, like storing the length separately; then you don't need the termination byte, and the risk of going out of bounds is lower. (With the zero-termination, you can accidentally either forget to add the zero, or forget to allocate space for it, or accidentally overwrite it, causing almost infinite loops (until there is a zero byte in memory by luck). These bugs are the reason for a bunch of "safer" library functions like snprintf instead of sprintf).

For such a simple use case, there is no compelling reason why you should implement any more complexity on your own. The zero-termination comes with traps and risks of bugs, but implementing a more complex string system comes with the risk of bugs, as well.

Use the simple few-liner already posted, but make sure you understand how it works.
« Last Edit: March 15, 2020, 08:20:35 am by Siwastaja »
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: text / strings in C
« Reply #16 on: March 15, 2020, 08:56:09 am »
You may find it's better to add more functionality.  Reasons include non-blocking functions, shared use (i.e., from many functions, .c files), standardizing interface (could map it to stdout for example), etc.

For example, writing a string to the display could take up whole milliseconds at a time, precious time that might need to be spent polling devices or responding to interrupts.  Not that the write function would be interrupt-blocking, but it has to be if you want to get debug output from interrupt sources...

If it's buffered, like stdout, you don't have to worry about where or when data is sent.  As long as the buffer is updated atomically (usually by disabling interrupts, so it should be done quickly, too), it can receive data from any source (main or interrupt).

Downside is the buffer can fill up, so you do need to add checks for that.  Much better than completely missing a critical operation though.

Last time I did a HD44780 display, I used a buffer with in-band signaling.  Think it was that chars 0-7 were taken over for special functions (locate cursor, clear screen, etc.), and the rest are normal, like 8-15 are the programmable ones (CRAM) which are mirrored in that range so there's no loss of functionality, and 32-255 are normal.

Forget what string format I used on that project... it was a while ago.  I prefer to avoid ASCIIZ strings, the downside is fixed-length strings have to be passed by two parameters at all times (pointer and length), and the length is limited (whatever fits in a, char, short, whatever).

Of course if you're doing simple sequential stuff, basically doing Arduino stuff, blocking write functions are perfectly fine, too.

Tim

Why not use interrupts so that the ports is left to transmit while the rest of the program carries on and then the interrupt call loads the next character until it ends. Obviously more complicated. The maximum SPI frequency appears to be 2MHz but of  course if this is wired to the display a lower frequency is probably more prudent.

At 2MHz that is 4.5µs per character or 72µs per 16 character line.
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21651
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: text / strings in C
« Reply #17 on: March 15, 2020, 09:17:50 am »
Precisely -- and when the transmitter finishes, the interrupt has to read from somewhere asynchronously.  Hence, the buffer.  So you have a buffer, and the getters/setters to access it safely.  Simple once you've done it a few times. :)

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4026
  • Country: nz
Re: text / strings in C
« Reply #18 on: March 15, 2020, 10:19:28 am »
Of course strings are a thing in C. C strings are series of bytes in memory, terminated with value 0.

That's purely a convention. The compiler happens to support a convenient syntax for making global arrays containing constant strings i.e. "Hello" instead of {'H', 'e', 'l', 'l', 'o', '\0'} or even {72, 101, 108, 108, 111, 0} but that's .. *all*. And there are some completely optional-to-use functions such as strlen and strcpy and strcmp in the standard library.

Even *character* isn't a proper type in C -- it's just a small integer. You don't even know whether it's signed or unsigned.

None of the string library functions (not even strdup) care how you allocated the memory space for your zero-terminated series of bytes in memory. You could use a global array, a local variable, something allocated on the heap, or a pointer to any random byte in the middle of any of those -- or completely outside those. Nothing cares, nothing checks. You can allocate one big chunk of memory and then store a bunch of "strings" inside it. You can make the tails of strings overlap. Whatever.

All of this is *totally* foreign to users of languages such as Python, Perl, PHP, Ruby, JavaScript, Java, C# in which "string" is a real thing.
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21651
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: text / strings in C
« Reply #19 on: March 15, 2020, 10:50:48 am »
What's more, any named variable is simply a pointer to memory; so you can have the valid program,

Code: [Select]
int main = { ... };

Where "..." is the machine code for main().

Or, I forget if the compiler complains that it's not a function type and there's some type abuse to make it work.  But anyway, such an approach holds the honor of having forced an IOCCC (International Obfuscated C Code Challenge) rule change, namely that programs must be portable, not specific to CPUs or hardware. ;D

An aside: any executable statement simply gets compiled, eventually into machine code; can you place arbitrary statements within array initializers and have them compile?  Or do you need to write a function and read its contents to do that?  Never tried...  Also, how does it know, does it know that an array type can only have numeric initializers, and a function can only have statement initializers?  So in effect, the comma operator is context sensitive?

Conversely, you can commit such horrors as:

Code: [Select]
strcmp((char*)main, machine_code_to_compare_to)

But be careful doing

Code: [Select]
strcmp((char*)main(some_params), other_pointer_to_compare_to)

because main returns int so it better be some very special int where valid memory happens to be found... not to mention managing the correct recursion conditions. :D  (Recursive main() being another favorite of IOCCC entries.)

Tim
« Last Edit: March 15, 2020, 10:54:05 am by T3sl4co1l »
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: text / strings in C
« Reply #20 on: March 15, 2020, 12:06:09 pm »
I think basically the "string" and 'char' are just a way to tell the compiler that the character is not to be taken literally but converted to an 8 bit ASCII code. So we can read what we wrote and the compiler knows what we mean and puts the right value.

I expect my first move is to send a string to the display with waits for the buffer empty flag and then convert it to an interrupt driven function using a global variable.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: text / strings in C
« Reply #21 on: March 15, 2020, 02:25:39 pm »
Right, I get it. With pointers I can tell "a" function to send "any" string, bit more difficult to write code to pass "any" variable but i can pass the pointer.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17814
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: text / strings in C
« Reply #22 on: March 15, 2020, 02:28:26 pm »
The advantage of using an array for something like a display is that given the semi autonomy of the hardware and the ease of just refreshing the whole display an array can act as the "display ram" where I can put any text that is due to appear in the next screen load.
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21651
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: text / strings in C
« Reply #23 on: March 15, 2020, 03:10:49 pm »
On that note -- on the upside, character displays are fairly light weight, so it's not unreasonable to use a (full screen) framebuffer.  It's only 80 bytes even for a larger display (e.g. 4x20).  This would probably be best done by getter/setter functions to manage the buffer, and a low priority refresh (can be done say by main() loop polling), copying the whole framebuffer to the display regardless of how much has changed.

This of course gets a lot less practical on larger, and especially graphic, displays.  Even the classic 80x25 text screen needs 4kB, a huge amount for say an Arduino (but, still quite practicable for many ARM platforms).

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline Yansi

  • Super Contributor
  • ***
  • Posts: 3893
  • Country: 00
  • STM32, STM8, AVR, 8051
Re: text / strings in C
« Reply #24 on: March 15, 2020, 03:39:50 pm »
Note that most displays have painstakingly slow interfaces, so rather then wasting multiple thousands or even more CPU cycles on fetching a byte back from the display, you better buffer it internally for fast access whenever required.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf