By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,627 Members | 1,188 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,627 IT Pros & Developers. It's quick & easy.

Should embedded systems compilers be trusted

P: n/a

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.
Jun 27 '08 #1
Share this Question
Share on Google+
20 Replies


P: n/a

"Tomás Ó hÉilidhe" <to*@lavabit.comwrote in message
news:02**********************************@26g2000h sk.googlegroups.com...
>
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.
In most embedded compilers I've used, they've had a section either in the
on-line help for the package or in the manual where they summarized the
standard they were targeting (such as C89) and what their variations from
that were. Items such as the storage location of consts and stack behavior
are pretty common for those I've used. Some other compilers, on the other
hand, have had a comment somewhere that they were "based on C" or "having
roots in C" or some such. In these cases all bets were pretty much off.

For the items you mention (size of ints/longs, conversion) the packages
often supply definitions (i16, int32, uint8) which you'd use instead of the
standard names to ensure that the sizes you've coded for are kept and are
quite explicit on how conversions are done. Even with these, I usually put
a bit of code as early in the system as I can that verifies the coding
assumptions about sizes, conversions, stack operation, initialization and so
on and stops the machine with some error indication if they're wrong. These
tests should really only ever trigger in the development environment, and
you might figure they'd never really happen, but I have had them go off a
couple of times (usually right after a development package upgrade) and
they've saved me a lot of grief tracking down what would have been subtle
bugs. In one case one of them triggered when the part was changed due to
the way it handled I/O 16 bit quantities. The earlier part only had 8 bit
I/O, the new one had 8 and 16, but the previous engineer had assumed he
could throw 16 bit data and a 8 bit port and it would truncate the bits for
him. Well, it did, but the new part worked it differently. When code space
was limited, I'd put these tests in some #define for debug or development.

You might try comp.arch.embedded for this question. From what I've seen
over the years, this group pretty much assumes you're using a compliant
compiler.

- Bill

Jun 27 '08 #2

P: n/a
On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe
<to*@lavabit.comwrote:
>
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
Jun 27 '08 #3

P: n/a
On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe
<to*@lavabit.comwrote in comp.lang.c:
>
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.
Right, or for any other unsigned type, (unsigned type)-1. Or if you
are assigning or initializing any unsigned integer type, just plain
old ordinary -1.
Also, I might rely on things such as:

memset(data,-1,sizeof data)

to set all bits in a chunk of memory to 1.
Really? I never have, can't think of anybody who has. Do you really
do this? Why? I've never had a need for a block of memory with all
bits 1. Of course, if the array is of one of the unsigned integer
types, you're safe unless these types contain padding, and I've never
heard of that it anything used for embedded wok.
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.
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?
2) There's no stack used by default; you must define a function as
"reentrant" if you want a stack.
This one is a true gotcha on some of the small, antique 8-bitters.
They have severe hardware limitations on the size of the stack. I
don't (won't) use PIC, the architecture is too bizarre without
sufficient reason, but 8051 derivatives have the same issue.
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:
Frankly, you are asking the wrong question. And even if it is the
right question, you should probably be asking it on comp.arch.embedded
rather than here.

"Trust" is not the right word. Most embedded compilers, especially
those which call themselves "ANSI C" compiler (which is all of them),
provide a subset of the C language and therefore aren't really
conforming at all.
1) int being at least 16-Bit
ISTM one compiler, I think for much older PICs which had even more
limitations that had a 12-bit int.
2) long being at least 32-Bit
I also seem to remember one embedded compiler that had used something
less than 32 bits for long.
3) Compliant conversion between signed and unsigned types

I'm using the PIC C compiler to program the PIC16F684 chip.
As others have pointed out, just about every compiler comes with
documentation, either hard copy or electronic. The documentation will
tell you what the compiler does in these, and other cases.

But I still think "trust" is the wrong concept. C was designed (and
defined) as an efficient systems computing language for general
computing. Many of its features, and its efficiency, make it
extremely useful for embedded systems. But many embedded systems have
hardware architectures that make a full implementation of C either
completely impossible or incredibly impractical.

If you are using a new compiler for a new architecture, familiarize
yourself with its documentation, especially in areas of the language
that are "implementation-defined", and areas where it documents
limitations or omissions in conforming to the standard.

If anything is still questionable after reading and understanding the
documentation, contact the vendor's tech support, if such exists. Or
even better, write and build code. See what it does by examining the
object code generated, or by testing the code.

The concept of "trust" for an embedded compiler, in the sense you use
it here, seems at odds with the kind of due diligence I would expect
an experienced embedded systems developer to do.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
Jun 27 '08 #4

P: n/a
Jack Klein <ja*******@spamcop.netwrites:
On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe
<to*@lavabit.comwrote in comp.lang.c:
>>
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.

Right, or for any other unsigned type, (unsigned type)-1. Or if you
are assigning or initializing any unsigned integer type, just plain
old ordinary -1.
>Also, I might rely on things such as:

memset(data,-1,sizeof data)

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

Really? I never have, can't think of anybody who has. Do you really
do this? Why? I've never had a need for a block of memory with all
bits 1.
Which means nothing to those of us who have. And there are/were multiple
reasons and scenarios for just this. I'm unsure as to why you explain
what you may or may not have done when the poster is talking about why
he uses this.

Jun 27 '08 #5

P: n/a
On Apr 20, 2:28 pm, Barry Schwarz <schwa...@dqel.comwrote:
On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe

<t...@lavabit.comwrote:
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.
What makes you think that?

--
Robert Gamble
Jun 27 '08 #6

P: n/a
Tomás Ó hÉilidhe wrote:
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.

--
Peter
Jun 27 '08 #7

P: n/a
On Sun, 20 Apr 2008 15:21:23 -0700 (PDT), Robert Gamble
<rg*******@gmail.comwrote:
>On Apr 20, 2:28 pm, Barry Schwarz <schwa...@dqel.comwrote:
>On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe

<t...@lavabit.comwrote:
>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.

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
Jun 27 '08 #8

P: n/a
Jack Klein <ja*******@spamcop.netwrites:
On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe
<to*@lavabit.comwrote in comp.lang.c:
[...]
>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.

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.

[...]

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #9

P: n/a
On Apr 20, 11:59 pm, Barry Schwarz <schwa...@dqel.comwrote:
On Sun, 20 Apr 2008 15:21:23 -0700 (PDT), Robert Gamble

<rgambl...@gmail.comwrote:
On Apr 20, 2:28 pm, Barry Schwarz <schwa...@dqel.comwrote:
On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe
<t...@lavabit.comwrote:
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.
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.
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.

--
Robert Gamble
Jun 27 '08 #10

P: n/a
Peter Nilsson wrote:
Tomás Ó hÉilidhe wrote:
> 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.
Only on 2s-complement systems, as Barry pointed out.
OTOH (unsigned char)-1 always works.

--
Hallvard
Jun 27 '08 #11

P: n/a
In article <99********************************@4ax.com>,
Barry Schwarz <sc******@dqel.comwrote:
>On Sun, 20 Apr 2008 04:18:56 -0700 (PDT), Tomás Ó hÉilidhe
<to*@lavabit.comwrote:
>>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.
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?

--
"Product of a myriad various minds and contending tongues, compact of
obscure and minute association, a language has its own abundant and
often recondite laws, in the habitual and summary recognition of
which scholarship consists." -- Walter Pater
Jun 27 '08 #12

P: n/a
Hallvard B Furuseth wrote:
Peter Nilsson wrote:
Tom�s � h�ilidhe wrote:
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.

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) ..."

--
Peter
Jun 27 '08 #13

P: n/a
On Mon, 21 Apr 2008 15:11:17 -0700 (PDT), Peter Nilsson
<ai***@acay.com.auwrote:
>Hallvard B Furuseth wrote:
>Peter Nilsson wrote:
Tom?s ? h?ilidhe wrote:
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.

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

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?
>
>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) ..."

Remove del for email
Jun 27 '08 #14

P: n/a
In article <1m********************************@4ax.com>,
Barry Schwarz <sc******@dqel.comwrote:
>On Mon, 21 Apr 2008 15:11:17 -0700 (PDT), Peter Nilsson
<ai***@acay.com.auwrote:
>>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?
That darned undefined behaviour again! Some people end up with
nostral daemons, some people end up with titles and 317 years back
taxes...
--
"Product of a myriad various minds and contending tongues, compact of
obscure and minute association, a language has its own abundant and
often recondite laws, in the habitual and summary recognition of
which scholarship consists." -- Walter Pater
Jun 27 '08 #15

P: n/a
Barry Schwarz wrote:
>
.... snip ...
>
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.
But, if you get rid of the silly cast, with:
unsigned long x = -1;
the problem should go away, and you will load ULONG_MAX.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
** Posted from http://www.teranews.com **
Jun 27 '08 #16

P: n/a
Barry Schwarz writes:
>On Mon, 21 Apr 2008 15:11:17 -0700 (PDT), Peter Nilsson
<ai***@acay.com.auwrote:
>>Hallvard B Furuseth wrote:
>>>Only on 2s-complement systems, as Barry pointed out.
The Barry is wrong.
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.

--
Hallvard
Jun 27 '08 #17

P: n/a


Tomás Ó hÉilidhe wrote:
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
wa****@bytecraft.com


Jun 27 '08 #18

P: n/a
On Apr 21, 10:14*pm, rober...@ibd.nrc-cnrc.gc.ca (Walter Roberson)
wrote:
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.
Jun 27 '08 #19

P: n/a
On Apr 21, 7:42*am, Keith Thompson <ks...@mib.orgwrote:
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.
Jun 27 '08 #20

P: n/a
Tomás Ó hÉilidhe wrote:
On Apr 21, 7:42 am, Keith Thompson <ks...@mib.orgwrote:
>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.
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.

--
Ian Collins.
Jun 27 '08 #21

This discussion thread is closed

Replies have been disabled for this discussion.