Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Honored Contributor I
2,215 Views

sscanf and sprintf

1. Version 13.0 vs 12.1sp1 

 

Recently we try the version 13.0 with our working software in 12.1sp1 but we have a surprise it was not working properly. 

We have found why, it is because the compiler does not threat the structure and union address alignment the same way as the 12.1 (padding). 

Me and Frédéric Fortin have try to find the release note for the compiler but nothing is available. 

We try to use the "#pragma pack(2) " but without success. 

 

So could we have a complete documentation about the gcc compiler version you use and have the release note of this one. 

 

For now we come back to version 12.1sp1 

 

2. sprintf vs sscanf 

 

I try to use sprintf to serialise data to my memory (eeprom or flash) because structure and union are not threat the same way (see my previous coment). 

So with sprintf I could format the output to my memory and be sure to have the same format even if your gcc compiler change and read it back with sscanf. 

But my test was not so good. I try to use sprintf to generate my output stream for my memory and found that the format specifiers are not correctly threat as well for sscanf. 

 

I also have some warning messages when I compile, why ? 

 

warning: warning: close is not implemented and will always fail 

warning: warning: lseek is not implemented and will always fail 

warning: warning: read is not implemented and will always fail 

warning: warning: write is not implemented and will always fail 

 

For the test I have made with sprintf and sscanf, I put you in attachment the C code I use for my test (it is a text file). 

 

Decimal Format 

sprintf : The stream output is perfect 

sscanf : the value read back are not good for Test_INT8 = 10 and Test_UINT8 = 0, it should be Test_INT8 = -10 and Test_UINT8 = 10 

 

Hexadecimal Format 

sprintf : The stream output is practically perfect, except for Test_INT8 because it generate an output of 4 character length (FFF6) and it should be (F6) 

sscanf : the value read back are not good for Test_INT8 = 10 and Test_UINT8 = 0, it should be Test_INT8 = -10 and Test_UINT8 = 10 

 

To have a reference for the formatting specifier 

 

cplusplus.com/reference/cstdio/scanf/ 

cplusplus.com/reference/cstdio/printf/ 

 

 

 

0 Kudos
5 Replies
Highlighted
Honored Contributor I
110 Views

The alignment rules for structures and unions won't have changed. 

So you code is probably making assumptions about the way that C is compiled that the optimiser doesn't have to obey. 

Most likely because you are aliasing different types, search the web for 'strict aliasing'. 

 

Your printf() calls are probably generating 'incorrect' output because 'char' is always converted to 'int' before being passed as a parameter and gets sign extended on the way ('unsigned char' is also converted to 'int' - not 'unsigned int'). 

My guess is that scanf() is doing odd things because you are passing the address of 'char' or 'short' variables without using the correct format and that adjacent memory locations are being overwritten. I avoid scanf(), typically using strtoul() to parse numbers. 

 

I would also completely bypass all of the 'file' interfaces when writing to flash on an embedded system. You just need to expose and appropriate interface that directly accesses the underlying memory - there is no need for multiple layers of abstraction.
0 Kudos
Highlighted
Honored Contributor I
110 Views

Thanks a lot for the answer 

 

Question 1: 

 

For alignement it is confirm that the same structure compile with 13 and 12.1sp1 is not addressing the same way. 

example :  

 

struct sMySubStruct 

unsigned long Var2; // 32 bits 

 

struct sMyStruct 

unsigned short Var1; // 16 bits 

struct sMySubStruct Sub; 

 

Version 12.1sp1 addressing for Var1 = 0x00078704 and for Var2 = 0x00078706, so the size of Var1 = 2 bytes, no padding 

Version 13.0 addressing for Var1 = 0x00078704 and for Var2 = 0x00078708, so the size of Var1 = 4 bytes, with 2 bytes padding 

 

Question 2 : 

 

My output is generating perfectly because I could see it into the buffer in hexadecimal but when you use %.2hhX it generate 4 character long string. 

 

try this 

 

signed char Test_INT8 = -10; 

char Buffer[10]; 

 

sprintf(Buffer, "%hhi", Test_INT8); // Output = "-10" 

scanf(Buffer, "%hhi", &Test_INT8); // Read value is -1 "NOT GOOD" 

 

sprintf(Buffer, "%.2hhX", Test_INT8); // Output = "FFF6" "NOT GOOD" Where asking for only 2 character output length, the good output should be "F6". "F6" it's the good hexadecimal value for -10. 

scanf(Buffer, "%2hhX", &Test_INT8); // Read value is 0 "NOT GOOD" 

 

And I use those functions sprintf and sscanf with hexadecimal output because of the bug in the question 1, I want to use this method to get rid of alignement problem and automatic padding, to serialize structure to save it into flash or eeprom with the smallest amount of bytes possible. Because the lowest access time possible because we have an interrupt each 66.6us and we should read this structure. 

 

And finally I bypass all the alt library of altera because the are to big and to slow, we don't need this abstraction layer, the code is bigger with and slower. 

All the peripheral are access directly, I have 17 years of coding experience in embedded system for high speed acquisition system.
0 Kudos
Highlighted
Honored Contributor I
110 Views

Unless some earlier header file has left a pragma (or similar) that packs structures active there should be two bytes of padding between 'Var1' and 'Sub'. 

It might be that the printf/scanf implementations aren't processing %hh properly, and that the cut-down versions don't support field widths properly either, also %i isn't standard, use %d. 

I would use 'unsigned char' on the printf() to avoid the need for %hh. 

IIRC Altera's printf() brings in about 70k of code, it is possible to write an snprintf() that is much, much smaller and a lot faster. 

In any case code like: 

static const char hex = "0123456789abcdef"; buf = hex; buf = hex; buf = hex; ... will be much faster.
0 Kudos
Highlighted
Honored Contributor I
110 Views

Thanks dsl 

 

I known that the best way for optimzation in speed and size for "1" function is to do something like your example.  

 

But let say you have about 100 Uart Ascii Serial protocol command (message length is between 20 to 100 bytes) to interpret and 100 structure to serialize to save it into flash or eeprom. 

To use a command like sprintf and sscanf clarify a lot your code and is more easy to understand and manage. 

I know that the function take memory a certain amount of space, but consider that those function are use more than 200 times, so you have to split by 200 the space of this function 

So your code will be smaller than to treath each case separatly like in your example 

 

Thanks a lot for the suggestion, but for know I think the best way should be sprintf and sscanf 

 

If you have another suggestion, feel free to suggest me
0 Kudos
Highlighted
Honored Contributor I
110 Views

In that case you'd to better writing you own functions that do just what you want. 

Especially is you are using the Altera printf/scanf code (which are probably pulled out of one of the libc libraries from somewhere). 

scanf() in particular is difficult to use correctly - badly formatted data has very unexpected effects.
0 Kudos