Should embedded systems compilers be trusted

  • Thread starter Tomás Ó hÉilidhe
  • Start date
T

Tomás Ó hÉilidhe

There are a few guarantees I exploit in the C Standard. For instance,
I might write

(unsigned)-1

to get the maximum value for an unsigned integer.

Also, I might rely on things such as:

memset(data,-1,sizeof data)

to set all bits in a chunk of memory to 1.

I'm using an embedded systems compiler now though and I'm hesitant to
trust it with things like this. I've already come across the following
quirks:

1) You can't define a variable as const unless it can be put in the
chip's ROM.
2) There's no stack used by default; you must define a function as
"reentrant" if you want a stack.

To the people here who have experience with embedded systems C
compilers, how do you feel about trusting its C compliance? Some
issues I'd be concerned about are:

1) int being at least 16-Bit
2) long being at least 32-Bit
3) Compliant conversion between signed and unsigned types

I'm using the PIC C compiler to program the PIC16F684 chip.
 
B

Barry Schwarz

There are a few guarantees I exploit in the C Standard. For instance,
I might write

(unsigned)-1

to get the maximum value for an unsigned integer.

The standard guarantees that values for unsigned integers behave
nicely when they wrap in either direction. However, your code will
not work for an integer type wider than int. For C89 you probably
need (unsigned long) -1L and for C99 (unsigned long long) -1LL.
Also, I might rely on things such as:

memset(data,-1,sizeof data)

to set all bits in a chunk of memory to 1.

This only works on 2s-complement systems.
I'm using an embedded systems compiler now though and I'm hesitant to
trust it with things like this. I've already come across the following
quirks:

1) You can't define a variable as const unless it can be put in the
chip's ROM.
2) There's no stack used by default; you must define a function as
"reentrant" if you want a stack.

To the people here who have experience with embedded systems C
compilers, how do you feel about trusting its C compliance? Some
issues I'd be concerned about are:

1) int being at least 16-Bit
2) long being at least 32-Bit
3) Compliant conversion between signed and unsigned types

I'm using the PIC C compiler to program the PIC16F684 chip.


Remove del for email
 
R

Robert Gamble

The standard guarantees that values for unsigned integers behave
nicely when they wrap in either direction. However, your code will
not work for an integer type wider than int. For C89 you probably
need (unsigned long) -1L and for C99 (unsigned long long) -1LL.

What makes you think that?
 
P

Peter Nilsson

Tomás Ó hÉilidhe said:
There are a few guarantees I exploit in the C Standard. For instance,
I might write

(unsigned)-1

to get the maximum value for an unsigned integer.

This is required behaviour for unsigned integer types.
Also, I might rely on things such as:

memset(data,-1,sizeof data)

to set all bits in a chunk of memory to 1.

That function need not be available on a freestanding implementation.
If it is available though, the behaviour should work as you describe.
I'm using an embedded systems compiler now though and I'm
hesitant to trust it with things like this. I've already come across
the following quirks:

1) You can't define a variable as const unless it can be put in the
chip's ROM.
2) There's no stack used by default; you must define a function as
"reentrant" if you want a stack.

To the people here who have experience with embedded systems C
compilers, how do you feel about trusting its C compliance? Some
issues I'd be concerned about are:

1) int being at least 16-Bit
2) long being at least 32-Bit
3) Compliant conversion between signed and unsigned types

I'm using the PIC C compiler to program the PIC16F684 chip.

Rather than asking if the code will work on possibly non-conforming
implementations, wouldn't it be better to get (or build) yourself some
conformance tests and only use compilers that _are_ conforming?

If the source is to be compiled by the client, then I suggest you
charge significant amounts of money for any service contract
you enter into based on whether they are using a conforming
compiler or not.
 
B

Barry Schwarz

What makes you think that?

For sake of discussion, let us assume a 16 bit int and a 32 bit long
and the common UINT_MAX and ULONG_MAX for these sizes.

The statement
unsigned long x = (unsigned)-1;
will set x to 65535 (the value of the right hand side) which is
0x0000ffff, hardly the maximum value for this unsigned long.


Remove del for email
 
K

Keith Thompson

Jack Klein said:
On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe


This is not a quirk. C does not define things like "ROM" or "RAM".
You told the compiler that you wanted to define an object that would
not be changed. The compiler obligingly put it into memory where it
could not be changed. What's your objection?

Suppose I want to define the following (inside a function):

const time_t now = time();

Or substitute for some other function for time() if it's a
freestanding implementation that doesn't support <time.h>.

"const" in C means read-only. It sounds like the C-like compiler
being described treats "const" as meaning truly constant, i.e.,
capable of being evaluated at compile time. If it requires
const-qualified objects at block scope to have constant initializers,
it's not a conforming C compiler.

[...]
 
R

Robert Gamble

For sake of discussion, let us assume a 16 bit int and a 32 bit long
and the common UINT_MAX and ULONG_MAX for these sizes.

The statement
unsigned long x = (unsigned)-1;
will set x to 65535 (the value of the right hand side) which is
0x0000ffff, hardly the maximum value for this unsigned long.

I certainly agree that (unsigned) -1 is not going to yield ULONG_MAX.
I took your original comment to imply that (unsigned long) -1 would
not produce the desired results without the L suffix, that is where my
objection stemmed from.
 
H

Hallvard B Furuseth

Peter said:
That function need not be available on a freestanding implementation.
If it is available though, the behaviour should work as you describe.

Only on 2s-complement systems, as Barry pointed out.
OTOH (unsigned char)-1 always works.
 
W

Walter Roberson

On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe
This only works on 2s-complement systems.

C89 4.11.6.1 The memset Function

Description

The memset function copies the value of c (converted to an
unsigned char) into each of the first n charactes of the object
pointed to by s.


From this we can deduce that memset with value -1 will write UCHAR_MAX
to the n locations.

Is there ever a time when UCHAR_MAX is not all bits 1? The definition
of unsigned (C89 3.1.2.5) indicates that,

For each of the signed integer types, there is a corresponding
(but different) unsigned integer type (designated by the keyword
unsigned) that uses the same amount of storage (including
sign information) [...]

And doesn't C99 guarantee that unsigned char will have no padding bits
or trap representations?
 
P

Peter Nilsson

Hallvard said:
Only on 2s-complement systems, as Barry pointed out.

The Barry is wrong.
OTOH (unsigned char)-1 always works.

Which is precisely what memset will do.

7.21.6.1p2 "The memset function copies the value of c
(converted to an unsigned char) ..."
 
B

Barry Schwarz

The Barry is wrong.

When there was more than one of me, I could always depend on one of
the others to catch any mistakes. Now that I've been singularized, I
guess I should be more careful. Is there an estate that comes with
the title? Or better yet rents and royalties?
Which is precisely what memset will do.

7.21.6.1p2 "The memset function copies the value of c
(converted to an unsigned char) ..."


Remove del for email
 
W

Walter Roberson

On Mon, 21 Apr 2008 15:11:17 -0700 (PDT), Peter Nilsson
When there was more than one of me, I could always depend on one of
the others to catch any mistakes. Now that I've been singularized, I
guess I should be more careful. Is there an estate that comes with
the title? Or better yet rents and royalties?

That darned undefined behaviour again! Some people end up with
nostral daemons, some people end up with titles and 317 years back
taxes...
 
H

Hallvard B Furuseth

Yup, sorry.
When there was more than one of me, I could always depend on one of
the others to catch any mistakes. Now that I've been singularized, I
guess I should be more careful.

It's good to have company though.
 
W

Walter Banks

Tomás Ó hÉilidhe said:
To the people here who have experience with embedded systems C
compilers, how do you feel about trusting its C compliance? Some
issues I'd be concerned about are:

1) int being at least 16-Bit
2) long being at least 32-Bit
3) Compliant conversion between signed and unsigned types

I'm using the PIC C compiler to program the PIC16F684 chip.

Many (most) of the C compilers for small processors have
extensions specific to the target families they support. Of these
three issues.
1) int's 16 bit most will have at least an option to give you
16 bit ints many with have size specific declarations.

2) 32 bit longs. As with ints it will be available on most
compilers. If 32 bit math is needed you may want to be
very sure that a PIC 16F684 is the part you want to use.

3) conversion between signed and unsigned will likely be fine.

Re-entrant functions and dynamic memory allocation in
many small embedded processors may not be available.
Some of the small processors may not have the underlying
hardware support but the real reason is both re-entrant
function support and dynamic memory use in most small
embedded applications may not be good design practice.

Regards,


--
Walter Banks
Byte Craft Limited
Tel. (519) 888-6911
Fax (519) 746 6751
http://www.bytecraft.com
(e-mail address removed)
 
T

Tomás Ó hÉilidhe

C89  4.11.6.1 The memset Function

  Description

  The memset function copies the value of c (converted to an
  unsigned char) into each of the first n charactes of the object
  pointed to by s.

From this we can deduce that memset with value -1 will write UCHAR_MAX
to the n locations.


That's right. I actually put a hell of a lot of thought into this a
few months ago. Things are a little hairy simply because memset takes
an int rather than an unsigned char.

Giving it an int value of -1 will always result in it writing
UCHAR_MAX, and UCHAR_MAX will always be all-bits-one without any
padding.

I also went to the bother of writing a memset wrapper which would
allow you to give it an unsigned char.
 
T

Tomás Ó hÉilidhe

Suppose I want to define the following (inside a function):

    const time_t now = time();

Or substitute for some other function for time() if it's a
freestanding implementation that doesn't support <time.h>.

"const" in C means read-only.  It sounds like the C-like compiler
being described treats "const" as meaning truly constant, i.e.,
capable of being evaluated at compile time.


Exactly; your above line of code will fail to compile with the PIC C
compiler.
 
I

Ian Collins

Tomás Ó hÉilidhe said:
Exactly; your above line of code will fail to compile with the PIC C
compiler.

That's a bit of a (horrible) bug. Every embedded compiler I've used put
file scope const items in a read only segment, but not function scope ones.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top