C question -- init string without trailing null possible?

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I seem to recall a discussion on this in the past, but cannot find it.

 

I want to put an array of structs into flash.  (but flash or EEPROM or SRAM shouldn't matter, I don't think)  Each has a name field of exactly 8 bytes.  I want to give initial value, with no trailing null.  CodeVision objects:

 

Error: C:\OptiCode\HY148\HY148p.c(4660): initializer "string" exceeds array dimension

Stripped-down trivial example (yeah, I know if there were no other fields I could just paste them together...)

 

struct	xproduct_struct
{
unsigned char	type;		//
unsigned char	name[8];	//
};
typedef struct xproduct_struct	xxxProduct;

flash			xxxProduct	products_fixed[] =
{
	{	1, "DICTATE "},
	{	2, "FROGHAIR"},
};

I guess I could init each element of the array individually -- that would be onerous:

{ 2, {'F','R','O','G','H','A','I','R'}},

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Wed. Sep 27, 2017 - 07:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your code is correct and achieves what you want, initializing the array without the trailing null. Looks like a bug to me that the compiler doesn't accept it.

 

Edit:

 

The standard says:

An array of character type may be initialized by a character string literal or UTF−8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

 

Stefan Ernst

Last Edited: Wed. Sep 27, 2017 - 07:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:

Your code is correct and achieves what you want, initializing the array without the trailing null. Looks like a bug to me that the compiler doesn't accept it.

 

Edit:

 

The standard says:

An array of character type may be initialized by a character string literal or UTF−8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

 

 

Which standard is that from?

 

The problem with standards is...... there are so d*m many of them!

 

 

 

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:
Your code is correct and achieves what you want, initializing the array without the trailing null. Looks like a bug to me that the compiler doesn't accept it.

Well, poo -- I think you are right.  I poked into GCC/Studio7 and got a clean build with

...
struct	xproduct_struct
{
	unsigned char	type;		//
	unsigned char	name[8];	//
};
typedef struct xproduct_struct	xxxProduct;

__flash xxxProduct	const products_fixed[] =
{
	{ 2, {'F','R','O','G','H','A','I','R'}},
	{	1, "DICTATE "},
	{	2, "FROGHAIR"},
};
...
int main(void)
{
	myPWM_init();
	while(1)
	{
		OCR1C=9999;
		PORTB = products_fixed[0].name[PINB];
	}
}

...and the generated code looks reasonable -- I see the LPM...

154:	e3 b1       	in	r30, 0x03	; 3
 156:	f0 e0       	ldi	r31, 0x00	; 0
 158:	eb 51       	subi	r30, 0x1B	; 27
 15a:	ff 4f       	sbci	r31, 0xFF	; 255
 15c:	84 91       	lpm	r24, Z
 15e:	85 b9       	out	0x05, r24	; 5

... and the table in flash...

000000e4 <__trampolines_end>:
  e4:	02 46       	sbci	r16, 0x62	; 98
  e6:	52 4f       	sbci	r21, 0xF2	; 242
  e8:	47 48       	sbci	r20, 0x87	; 135
  ea:	41 49       	sbci	r20, 0x91	; 145
  ec:	52 01       	movw	r10, r4
  ee:	44 49       	sbci	r20, 0x94	; 148
  f0:	43 54       	subi	r20, 0x43	; 67
  f2:	41 54       	subi	r20, 0x41	; 65
  f4:	45 20       	and	r4, r5
  f6:	02 46       	sbci	r16, 0x62	; 98
  f8:	52 4f       	sbci	r21, 0xF2	; 242
  fa:	47 48       	sbci	r20, 0x87	; 135
  fc:	41 49       	sbci	r20, 0x91	; 145
  fe:	52 00       	.word	0x0052	; ????

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:
Which standard is that from?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is perfectly legal to initialise an 8 char array with a quoted string.   It should just drop the NUL if it does not fit.

Most Compilers will whinge but it should be Warning not Error.

 

Note that a 9-char string would be an Error.

 

char name[5] = "David";  //will omit the NUL

char name[] = "David";   //will allocate 6 chars to accommodate the NUL

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the eyes and the responses, people.  I'll work around it. Take care.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Wed. Sep 27, 2017 - 08:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your example compiles ok in imagecraft as well. 

No null char's stored.

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
It is perfectly legal to initialise an 8 char array with a quoted string.   It should just drop the NUL if it does not fit.

Learn someting every day: Check.

 

(I might actually have known this at some time, but iif so it sure is swapped out thoroughly..)

 

 

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

(I might actually have known this at some time, but iif so it sure is swapped out thoroughly..)

$ echo 3 > /proc/sys/vm/drop_caches

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW dropping the null is NOT valid in C++.

I note the file name ends in .c .

gcc can be told to compile a .c file as C++.

International Theophysical Year seems to have been forgotten..
Anyone remember the song Jukebox Band?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am disappointed that I can apparently not index quoted strings in initialization:

   char c = "mystring"[3];

(I mean, the compiler will optimize away references like that

static char* mystring = "mystring";
  :
  c = mystring[3];

will end up producing something like "ldi r24,'t'"...)

 

that would have made for some not-too-ugly macros for initializing size-limited arrays from arbitrary strings...   Ah well.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

I am disappointed that I can apparently not index quoted strings in initialization:

   char c = "mystring"[3];

Are you sure? I tried to compile this and there were no errors. It works for both C and C++.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sure? I tried to compile this and there were no errors. It works for both C and C++.

Failed for me with avr-gcc 5.4, 4.3.x, and Apple llvm 6.00

 

BillW-MacOSX-2<5027> avr-gcc -c -Os -mmcu=atmega8 gross.c
gross.c:5:10: error: initializer element is not constant
 char c = "1234"[2];
          ^

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

Are you sure? I tried to compile this and there were no errors. It works for both C and C++.

Failed for me with avr-gcc 5.4, 4.3.x, and Apple llvm 6.00

 

BillW-MacOSX-2<5027> avr-gcc -c -Os -mmcu=atmega8 gross.c
gross.c:5:10: error: initializer element is not constant
 char c = "1234"[2];
          ^

 

I know what makes the difference. My c variable was an automatic variable in main() and apparently your c was a global variable. When I moved the variable outside of main(), I also got compile error.

In early C string constants like "1234" in your example could be modified, but current standard doesn't allow this. However, string literals are still of type char[] in C, not const char[] and I think this is the reason why "1234"[2] isn't a constant expression.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I thought it might be that, but it also doesn't like casts to "const" either.

I guess the automatic variable initialization doesn't even need to be constant (but does optimized to an LDI...)