C99 Extensions in HCS08 and RS08 Compiler

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

C99 Extensions in HCS08 and RS08 Compiler

2,044 Views
carloscuevas
Contributor III

I know that for CF V1 we can enable C99 extensions wich I think are great for writing cleaner and more understandable code. But I cannot find the option in the Standard Settings window for a 8-Bit project, I tried enabling it with pragma (#pragma c99 on) but it makes a warining: "Warning : C4201 : pragma c99 was not handled" Is there any way to use C99 Extensions for the CW HCS08 & RS08 C compiler?

Labels (1)
Tags (1)
0 Kudos
7 Replies

633 Views
Lundin
Senior Contributor IV

I recently investigated this matter through Freescale support. The only C99 feature available on HC08 compilers is the // comments.

 

How exactly would C99 make the code cleaner and more understandable? To my knowledge there are no such features in C99, though plenty of the opposite.

0 Kudos

633 Views
carloscuev
Contributor V

//lets imagine that yopur application uses this struct:


typedef struct

{

  short startingRegister;

  char registerQuantity;

  short registerValuesBuffer[16];

  short checksum;

  short requestLength;

} modbusRequestData_t;


//if you want to initialize only requestLength with value 0x20 and index 3 of registerValuesBuffer[] array with value 0xFF:


// Without C99

modbusRequestData_t myRequest = {0, 0, {0, 0, 0, 0xFF}, 0, 0x20 };


//With C99

modbusRequestData_t myRequest = { .registerValuesBuffer[3] = 0xFF, requestLength = 0x20 };


//This C99 feature is called "Designated Initializers", there are other features that help to write more undestandable code

 

0 Kudos

633 Views
Lundin
Senior Contributor IV

I know of designated initializers. Personally I regard them as a pointless feature that doesn't make the code any clearer. No matter how you write initializer lists, it is not easy to read them when they get long-winded.

 

To me, the most readable (and C90-compatible way) would be:

 

modbusRequestData_t myRequest = {0};
myRequest.registerValuesBuffer[3] = 0xFF;
myRequest.requestLength = 0x20;

 

Assigning each member one by one has another big advantage: if the struct is declared static or global, it doesn't rely of static initialization when every member is set in "runtime". Code that doesn't rely on static initialization is more robust and suitable for embedded systems, as you can then remove the static initialization phase from your code and get a quicker program startup (which is especially important on 8-bit MCUs). Ie you have no tight coupling between the compiler-specific way of initializing statics/globals and your code.

0 Kudos

633 Views
carloscuev
Contributor V

I have one concern: compiled code size. Do you know which method is more efficient ?

 

You way of thinking is interesting, what do you think about Compound Literals, I think they are a very useful resource in C99. The way I have done lots of things in CFV1 (heavy pointer usage looking for compiled code size optimization) I can assure you my code is smaller and easier to expain to my colleagues when using them.

0 Kudos

633 Views
Lundin
Senior Contributor IV

This is what the compiler does by default:

 

- Allocate a segment in flash containing all init values for every static/global in your program. (Called "rodata" or some such.)

- Copy down these values from flash to your variables, at program startup.

- If you had explicitly initialized a static/global variable, ie "static int x = 5;", the value you wrote will be copied.

- If you didn't explicitly initialize it, the value 0 will be copied. This is required by ISO C.

 

The answer to your question depends on whether you have set your compiler to use the above method or not. In CW this is called "ANSI startup" or "minimal startup", which you pick when creating a new project. If you pick "ANSI", all your static/global variables will be initialized either to the init value you have written explicitly, or to zero. If you pick "minimal", the only thing the startup code will do is to set the stack pointer and then call main(). Your statics/globals will then not become initialized, even if you explicitly did so. You would have to set them all in runtime.

 

With ANSI startup code, you will have a for() loop sitting in flash memory, which copies down all init values from flash to RAM. The loop itself doesn't take much flash space, but consumes time at program startup.

 

With minimal startup, you will not have this loop, but you will have to setup your variables manually instead. With program space in regard, the difference versus "ANSI" will barely be notable.

 

However, when you do manual assignment of variables, there is a chance that the compiler will optimize the code, particularly for initializing to zero. This will reduce the flash segment of init variables. So in terms of flash memory consumption, you should avoid static/global initialization entirely.

 

---

 

Regarding compound literals, I find them as superfluous as designated initializers. Just another thing they just had to include in the language because other languages had similar constructs, even though "anonymous objects" are often considered poor style in those other languages, particularly for complex items such as classes/structs. They make the code cluttered up. Java is known to suffer a lot from it, I remember avoiding anonymous classes like the plauge in Java, just because they weren't readble when the code turned complex. Just look at this snippet:

 

typedef struct
{
  int x;
  int y;
}Some_struct;

int func (Some_struct* arg1, int arg2);

...

// Alternative 1, compound literal:
result = func (&(Some_struct){1,2}, 5);

// or if you will, with designated initializers:
result = func (&(Some_struct){.x=1,.y=2}, 5);

// Alternative 2, explicit declaration:
Some_struct ss;
ss.x = 1;
ss.y = 2;
result = func(&ss, 5);

To me, alternative 2 is far more readable even for this simple struct with only 2 members. The compound literals have a non-intuitive syntax and they seem mixed up with parameter arg2, which has nothing to do with the struct. The simple truth is: the more you merge non-related operations together on the same row, the messier the code turns out.

 

0 Kudos

633 Views
carloscuev
Contributor V

Does Codewarrior v10.0 (Eclipse based) has C99 support for S08 devices?

0 Kudos

633 Views
BlackNight
NXP Employee
NXP Employee

Hello,

There is currently no option to enable C99 for S08 and RS08.

BK