Does your C compiler support "//"? (was Re: using structures)

W

Wojtek Lerch

Dan Pop said:
Maybe they shouldn't, but they are. Since the requirement is only mentioned
in the paragraph dealing with signed types, it only applies to signed types.
This may be surprising and inconsistent, but it's not unclear.

It's not so clear for those familiar with the history of the document.
As late as N869, the text in question was:

7.18.1.1 Exact-width integer types

[#1] The typedef name intN_t designates a signed integer |
type with width N. Thus, int8_t denotes a signed integer |
type with a width of exactly 8 bits.

[#2] The typedef name uintN_t designates an unsigned integer |
type with width N. Thus, uint24_t denotes an unsigned |
integer type with a width of exactly 24 bits. |

OK, so between N869 and C99, the part about no padding was added to #1 but
not to #2. Notice that this is consistent with the fact that even though
6.2.5#6 requires that for each signed type there must be a corresponding
unsigned type, there's no requirement that works the other way around. You
can't have int8_t without uint8_t, but you can have uint8_t without int8_t.
The fourth bullet in 6.3.1.1#1 confirms this: "The rank of any unsigned
integer type shall equal the rank of the corresponding signed integer type,
*if any*". This all seems pretty consistent with the intention to allow
implementation to have exact-width unsigned types with padding, even if the
corresponding signed types cannot be implemented because they would need to
have padding, too.
It is perfectly possible that the intent is to exclude padding bits from
all the exact width integer types. This is strongly suggested by the
name "exact-width". The addition made after N869 is already known to

What does the exact width have with padding bits? It's exact width, not
exact size.
be inconsistent, as it is missing from the following text:
3 These types are optional. However, if an implementation provides
integer types with widths of 8, 16, 32, or 64 bits, it shall
define the corresponding typedef names.

rendering 7.18.1.1p3 inconsistent with 7.18.1.1p1.

Yes, DR #269 talks about this inconsistency. Notice that the Committee
didn't think that allowing the unsigned types to have padding is a defect,
only that changing it should be considered in a future revision of the
standard.
 
W

Wojtek Lerch

Douglas A. Gwyn said:
It's not necessary, due to corresponding signed and
unsigned types having to match up (requirement elsewhere).

There is a requirement that for every signed type, there must be a
corresponding unsigned type, but not the other way around. An
implementation with 9-bit bytes can have a uint8_t with one padding bit, but
it can't have an int8_t. Or have I missed something?
 
K

Keith Thompson

Wojtek Lerch said:
There is a requirement that for every signed type, there must be a
corresponding unsigned type, but not the other way around. An
implementation with 9-bit bytes can have a uint8_t with one padding bit, but
it can't have an int8_t. Or have I missed something?

unsigned char can't have padding bits, and all the other standard
types (short through long long) have to have ranges too big for
uint8_t. But I think there can be problems with larger sizes.
 
W

Wojtek Lerch

Keith Thompson said:
unsigned char can't have padding bits, and all the other standard
types (short through long long) have to have ranges too big for
uint8_t. But I think there can be problems with larger sizes.

Why are you mentioning standard types? Obviously, uint8_t would have to be
an extended type on an implementation with 9-bit bytes.
 
D

David Hopwood

Douglas said:
It's not necessary, due to corresponding signed and
unsigned types having to match up (requirement elsewhere).

Ah, yes: C99 7.18.1p1 and 6.2.5p6. So my original statement, that it is not
possible to support either uint8_t or int8_t when CHAR_BIT > 8, is correct,
which provides a strong justification for the POSIX requirement of
CHAR_BIT == 8.

David Hopwood <[email protected]>
 
W

Wojtek Lerch

David Hopwood said:
Ah, yes: C99 7.18.1p1 and 6.2.5p6. So my original statement, that it is not
possible to support either uint8_t or int8_t when CHAR_BIT > 8, is
correct,

I understand why it's impossible to support int8_t, but why uint8_t?
 
K

Keith Thompson

Wojtek Lerch said:
Why are you mentioning standard types? Obviously, uint8_t would have to be
an extended type on an implementation with 9-bit bytes.

Because I posted the article before I remembered to mention extended
types. Oops.
 
D

David Hopwood

David said:
Ah, yes: C99 7.18.1p1 and 6.2.5p6.

Although 6.2.5p6 seems to have a defect: "(designated with the keyword
unsigned)" contradicts 7.18.1p1. It should say:

# For each of the signed integer types, there is a corresponding (but
# different) unsigned integer type (designated with the keyword unsigned
# or as specified in 7.18.1) that uses the same amount of storage (including
# sign information) and has the same alignment requirements. [...]

David Hopwood <[email protected]>
 
D

David Hopwood

Wojtek said:
There is a requirement that for every signed type, there must be a
corresponding unsigned type, but not the other way around.

That's not correct; 7.18.1p1 says "an implementation providing one of these
corresponding types shall also provide the other."

David Hopwood <[email protected]>
 
W

Wojtek Lerch

David Hopwood said:
That's not correct; 7.18.1p1 says "an implementation providing one of these
corresponding types shall also provide the other."

Um... Yes, you're right, I missed that spot...
 
D

David Hopwood

Douglas said:
Unless you read my actual posting, you do not know
what I was arguing. Clive completely misrepresented it.

I have now read the original posting:

http://groups.google.co.uk/[email protected]

You have a point in saying that Clive's quoting did not preserve important
context. However, the statement that "the POSIX people have not understood
what was suggested by the Standard C people" is still inconsistent with the
rest of the post. It seems as though you really meant, "the POSIX people
understood the C Standard, but the C Standard doesn't follow my own idea
about how character types should have been defined, which would have been
better."
No, it wouldn't, because octets ought to be handled
via unsigned types.

Yes, it would, because the C string handling functions use char, and
for efficiency it's necessary to be able to cast directly between arrays
of char and arrays of unsigned char (not to mention the vast number of
existing C programs that do this, justifiably or not).

David Hopwood <[email protected]>
 
J

Jack Klein

[snip]
The section heading "Exact-width integer types" has certain
implications, and it says both u/int8_t must have exactly 8 bits.

If CHAR_BIT > 8, the implementation can support u/int_least8_t, as JK
also stated, in the part you snipped.


ICBW but are unsigned types allowed to have any padding bits?

6.2.6 Representations of types

6.2.6.1 General

[snip]

3 Values stored in unsigned bit-fields and objects of type unsigned
char shall be represented using a pure binary notation.

[snip]

6.2.6.2 Integer types

1 For unsigned integer types other than unsigned char, the bits of the
object representation shall be divided into two groups: value bits and
padding bits (there need not be any of the latter).
Hosted implementations are not likely, but that just makes support of
as much as useful of the standard library a QoI issue.
Porting network stacks is likely, and u/int_least8_t could help.

I have never done a TCP/IP stack, but I have implemented CAN networks
on parts like this.

We recently did one with our own custom protocol, a 32-bit ARM9 master
on one side and multiple CHAR_BIT 16 DSP slaves on the other. On the
DSP platform the CAN data section (0 to 8 octets) was only readable as
a pair of 32-bit words (on-chip peripheral on 32-bit data bus as
opposed to off-chip 16-bit bus).

In our protocol (and most others), the octets could represent any
number of 8, 16, or 32-bit values. There are issues on both sides.
On the ARM you can't just dump the 64 bits of data into memory and
pick out arbitrary sized values due to alignment requirements. On the
DSP you also have some alignment requirements (32-bit values must
align to even addresses), and no 8-bit memory addressability.

I wrote the DSP side of the interface first. The first level above
the ISR received the buffered data and called an unpacker, which
merely shifted and masked octets out of the two unsigned longs into an
array of 8 uint_least8_t's. Next the parser, working from a parser
based on the packet type in the address field, recombined the octets
into however many entries into an array of unions consisting of signed
and unsigned longs. A pointer to the first element of this array was
passed to handler function for the particular packet.

Output is pretty much the reverse. The calling packet places whatever
parameters into an array of unions. This is passed to driver entry
which uses a format string based on the packet type which unpacks the
unions into an array of uint_least8_t's again. The lower level part
of the driver packs the octets back into two 32-bit unsigned longs
again, ready to buffer for the ISR to write to the hardware.

The packing and unpacking code was so small that when one of my
colleagues got to writing the ARM side of the interface, he just
popped in the already tested and working code from the DSP. On the
ARM the intermediate step of packing/unpacking into uint_least8_t's
wasn't necessary, the ARM can walk a pointer to unsigned char through
the 32-bit words. But the few words of machine code generated by the
routines was not worth modifying and retesting.

All the types used (int32_t, uint32_t, uint_least8_t) were
specifically selected from <stdint.h> to be able to work with any 8-,
16-, or 32-bit platform (and probably most 64-bit platforms). The
only assumption was exact-width 32-bit types. I could have eliminated
this restriction with int_least32_t instead, now that I think of
it, but I didn't.
 
J

Jack Klein

Dan Pop said:
Although the standard is less than perfectly clear, it seems that the
exact-width integer types cannot have padding bits. The requirement is
explicitly mentioned only in the paragraph dealing with signed types,
but I can see no reason why exact-width unsigned types should be any
different:

Maybe they shouldn't, but they are. Since the requirement is only mentioned
in the paragraph dealing with signed types, it only applies to signed types.
This may be surprising and inconsistent, but it's not unclear.

It's not so clear for those familiar with the history of the document.
As late as N869, the text in question was:

7.18.1.1 Exact-width integer types

[#1] The typedef name intN_t designates a signed integer |
type with width N. Thus, int8_t denotes a signed integer |
type with a width of exactly 8 bits.

[#2] The typedef name uintN_t designates an unsigned integer |
type with width N. Thus, uint24_t denotes an unsigned |
integer type with a width of exactly 24 bits. |

OK, so between N869 and C99, the part about no padding was added to #1 but
not to #2. Notice that this is consistent with the fact that even though
6.2.5#6 requires that for each signed type there must be a corresponding
unsigned type, there's no requirement that works the other way around. You
can't have int8_t without uint8_t, but you can have uint8_t without int8_t.
The fourth bullet in 6.3.1.1#1 confirms this: "The rank of any unsigned
integer type shall equal the rank of the corresponding signed integer type,
*if any*". This all seems pretty consistent with the intention to allow
implementation to have exact-width unsigned types with padding, even if the
corresponding signed types cannot be implemented because they would need to
have padding, too.

No, you missed this:

7.18 Integer types <stdint.h>

[snip]

7.18.1 Integer types

1 When typedef names differing only in the absence or presence of the
initial u are defined, they shall denote corresponding signed and
unsigned types as described in 6.2.5; an implementation providing one
of these corresponding types shall also provide the other.
 
D

Douglas A. Gwyn

David said:
... It seems as though you really meant, "the POSIX people
understood the C Standard, but the C Standard doesn't follow my own idea
about how character types should have been defined, which would have been
better."

No, the quick summary of my posting is that instead of
specifying constraints on type char, POSIX should have
required uint8_t be supported, and used that typedef
uniformly for the network octet interface specs. And
I explained why I think it makes a difference.
Yes, it would, because the C string handling functions use char, ...

Where it matters, as for strcmp, there is an explicit
requirement that the bytes involved be treated as
unsigned char.
 
D

David Hopwood

Douglas said:
No, the quick summary of my posting is that instead of
specifying constraints on type char, POSIX should have
required uint8_t be supported, and used that typedef
uniformly for the network octet interface specs.

POSIX uses void * for buffer arguments to networking functions. This
was for compatibility with BSD sockets. While uint8_t * would have
been preferable but for the compatibility issue, void * does not cause
any significant problems, because an application can still declare the
buffers as arrays of uint8_t or unsigned char.
Where it matters, as for strcmp, there is an explicit
requirement that the bytes involved be treated as
unsigned char.

That doesn't address the issue that allowing plain char to have a
trap representation would have broken many existing programs, for no
good reason in the context of the platforms targetted by POSIX.

David Hopwood <[email protected]>
 
D

Douglas A. Gwyn

David said:
That doesn't address the issue that allowing plain char to have a
trap representation would have broken many existing programs, ...

No, the programs would work just as *they always have*.
 
D

Douglas A. Gwyn

David said:
Not necessarily on new POSIX platforms, even if the programs are
otherwise free of implementation-defined behaviour.

Do you know of new ones-complement or sign-magnitude
POSIX platforms?

This is another case of rewarding unnecessary poor
coding practice. It is pretty much the same as
restricting one's target to C implementations with
32-bit int type, due to having assumed "all the
world's a VAX".
 
D

David Hopwood

Douglas said:
Do you know of new ones-complement or sign-magnitude
POSIX platforms?

The issue here is whether the POSIX standard guarantees that there
will be no such platforms. Since it does, programmers of POSIX-portable
applications can rely on this. You're arguing that there are no such
platforms, but that programmers should not be allowed to rely on there
being no such platforms -- which makes absolutely no sense.

David Hopwood <[email protected]>
 
B

Brian Inglis

Do you know of new ones-complement or sign-magnitude
POSIX platforms?

Is there any POSIX support on UniSys OS2200? Being descended from the
Univac 1100 series, I'm pretty sure it's not 2sC, but I can't remember
if it's 1sC or SM.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top