Classification of arithmetic types

J

jacob navia

As Richard Bos rightly pointed out, I had left in my classification
of types the C99 types Complex and boolean. Here is a new
classification. Those are not mentioned in the classification
of Plauger and Brody, probably because their work predates
C99. Since there are no examples of this in the literature
(known to me) please take a look.

Thanks

3.1.1 Arithmetic types
3.1.1.1 Integer types
3.1.1.1.1 Specific integer types
3.1.1.1.1.1 boolean type
3.1.1.1.1.2 char (signed/unsigned)
3.1.1.1.1.3 short (signed unsigned)
3.1.1.1.1.4 int (signed/unsigned)
3.1.1.1.1.5 long (signed/unsigned)
3.1.1.1.1.6 long long (signed/unsigned)
3.1.1.1.2 Bitfields (signed/unsigned)
3.1.1.1.3 Enumeration types
3.1.1.2 Floating types
3.1.1.2.1 Real types
3.1.1.2.1.1 float
3.1.1.2.1.2 double
3.1.1.2.1.3 long double
3.1.1.2.4 Complex types
3.1.1.2.4.1 float Complex
3.1.1.2.4.2 double Complex
3.1.1.2.4.2 long double Complex

I would define arithmetic types as those that define the 4 operations.
This distiguishes them from pointer types where addition and
subtraction are defined but not multiplication/division.

Is that correct?

jacob

E

Eric Sosman

jacob said:
As Richard Bos rightly pointed out, I had left in my classification
of types the C99 types Complex and boolean. Here is a new
classification. Those are not mentioned in the classification
of Plauger and Brody, probably because their work predates
C99. Since there are no examples of this in the literature
(known to me) please take a look.

Thanks

3.1.1 Arithmetic types
3.1.1.1 Integer types
3.1.1.1.1 Specific integer types
3.1.1.1.1.1 boolean type
3.1.1.1.1.2 char (signed/unsigned)

Also "plain old char," a third type distinct from the other
two (even though it behaves identically to one of them).
3.1.1.1.1.3 short (signed unsigned)
3.1.1.1.1.4 int (signed/unsigned)
3.1.1.1.1.5 long (signed/unsigned)
3.1.1.1.1.6 long long (signed/unsigned)

How about wchar_t, size_t, ptrdiff_t, sig_atomic_t, wint_t,
and the said:
3.1.1.1.2 Bitfields (signed/unsigned)
3.1.1.1.3 Enumeration types
3.1.1.2 Floating types
3.1.1.2.1 Real types
3.1.1.2.1.1 float
3.1.1.2.1.2 double
3.1.1.2.1.3 long double

float_t and double_t?
3.1.1.2.4 Complex types
3.1.1.2.4.1 float Complex
3.1.1.2.4.2 double Complex
3.1.1.2.4.2 long double Complex

time_t, clock_t, wctrans_t, and wctype_t are difficult to
categorize.

J

jacob navia

Eric Sosman a écrit :
Also "plain old char," a third type distinct from the other
two (even though it behaves identically to one of them).
How about wchar_t, size_t, ptrdiff_t, sig_atomic_t, wint_t,
and the <stdint.h> types?
time_t, clock_t, wctrans_t, and wctype_t are difficult to
categorize.

As far as I understood this stuff, all those are defined in terms of
one of the primitive types in the enumeration above.
For instance, in many implementations size_t is unsigned long,
or time_t is long long, or clock_t is int, etc etc.

They are derived types defined in terms of a more primitive type.

The same applies to chart ("plain" char) since it is defined either
as unsigned or signed char, what means it is not another basic
type but a synonym for one of the char types.

J

jacob navia

jacob navia a écrit :
The same applies to chart ("plain" char)

Not "chart" but "char" of course. Excuse me.

R

Richard Bos

jacob navia said:
Eric Sosman a écrit :

As far as I understood this stuff, all those are defined in terms of
one of the primitive types in the enumeration above.

Not necessarily. For example, on historic implementations, time_t was
often larger than a single long, and was therefore a struct. Ditto for,
e.g., fpos_t. The point about such types is that they may be one
specific primitive type on any particular implementation, but to the
wise C programmer they must remain abstract types. As such, they deserve
discussion.

Richard

E

Eric Sosman

jacob said:
Eric Sosman a écrit :

As far as I understood this stuff, all those are defined in terms of
one of the primitive types in the enumeration above.
For instance, in many implementations size_t is unsigned long,
or time_t is long long, or clock_t is int, etc etc.

"In many implementations" doesn't quite make the grade for
a treatise that is supposed to be about the language and not
about particular implementations of it. "In many implementations"
it is true that INT_MIN < -INT_MAX, but that's not true of the
language per se.

Even in C90 I'm not entirely sure that all the "named for a
purpose" types were required to be aliases of "ordinary" types as
opposed to implementation-defined "exotic" types. Certainly in
C99 the lid came off, and int_least16_t (for example) might not
be a synonym for any kind of char, short, or int.
The same applies to chart ("plain" char) since it is defined either
as unsigned or signed char, what means it is not another basic
type but a synonym for one of the char types.

The Standard disagrees with you (6.2.5/14). `char' is a
type unto itself, distinct from both `signed char' and
`unsigned char'. `int' and `short' are distinct types even
when both are 16 bits wide; `int' and `long' are distinct even
when both are 32 bits wide; `double' and `long double' are
distinct even when both are IEEE double-precision numbers.
Representation and behavior are not the sole ingredients of
"type."

P

P.J. Plauger

For an update of the Plauger & Brodie documentation, see the C
portion of our on-line manual:

http://www.dinkumware.com/manuals/
Also "plain old char," a third type distinct from the other
two (even though it behaves identically to one of them).

How about wchar_t, size_t, ptrdiff_t, sig_atomic_t, wint_t,

float_t and double_t?

time_t, clock_t, wctrans_t, and wctype_t are difficult to
categorize.

What the standard says about each of these types is summarized
in our manual.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com

J

jacob navia

P.J. Plauger a écrit :
For an update of the Plauger & Brodie documentation, see the C
portion of our on-line manual:

http://www.dinkumware.com/manuals/

What the standard says about each of these types is summarized
in our manual.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com

Thanks for your answer Mr Plauger but I could not find that type
classification there. Maybe you would give a more specific link?
I browsed a lot of C stuff (and C++ stuff) but could not find it.

Thanks

K

Keith Thompson

jacob navia said:
Eric Sosman a écrit :

As far as I understood this stuff, all those are defined in terms of
one of the primitive types in the enumeration above.
For instance, in many implementations size_t is unsigned long,
or time_t is long long, or clock_t is int, etc etc.

They're typedefs for some predefined integer type, possible an
extended integer type (which you didn't mention).

Incidentally, be careful with the word "enumeration" in this context.
They are derived types defined in terms of a more primitive type.

No, the standard defines the term "derived type" (C99 6.2.5p20);
typedefs do not create derived types. If you're going to invent
terminology, be *very* careful to remain consistent with the standard.
Better yet, just use the standard's own terminology.
The same applies to chart ("plain" char) since it is defined either
as unsigned or signed char, what means it is not another basic
type but a synonym for one of the char types.

No, type char is distinct from both signed char and unsigned char,
though it has the same characteristics as one of them. This usually
doesn't matter due to implicit conversions, but these types:

char*
unsigned char*
signed char*

are all incompatible; values of these types cannot be assigned to each
other without a cast. If char were an alias for either signed char or
unsigned char, this would not be the case. (Does lcc-win32 get this
right?)

K

Keith Thompson

Not necessarily. For example, on historic implementations, time_t was
often larger than a single long, and was therefore a struct. Ditto for,
e.g., fpos_t. The point about such types is that they may be one
specific primitive type on any particular implementation, but to the
wise C programmer they must remain abstract types. As such, they deserve
discussion.

Yes, but the standard specifically requires time_t to be an arithmetic
type (though there's not much you can do in portable code to take

K

Keith Thompson

jacob navia said:
I would define arithmetic types as those that define the 4 operations.
This distiguishes them from pointer types where addition and
subtraction are defined but not multiplication/division.

Is that correct?

You don't get to define "arithmetic types". The term is defined in
C99 6.2.5p18. (I believe your definition happens to match the
standard's definition.)

Read C99 6.2.5 before you speculate.

J

jacob navia

Keith Thompson a écrit :
You don't get to define "arithmetic types". The term is defined in
C99 6.2.5p18. (I believe your definition happens to match the
standard's definition.)

Read C99 6.2.5 before you speculate.

The standard just says:

"Integer and floating types are collectively called arithmetic types."

This definition is just an enumeration, not a functional
definition, that I would prefer.

But this is not very important since the end result is the same.

J

jacob navia

Keith Thompson a écrit :
No, type char is distinct from both signed char and unsigned char,
though it has the same characteristics as one of them.

Mmmmm

" char is distinct from both signed char and unsigned char,
though it has the same characteristics as one of them" ...

I have some difficulty following you here. If it has the same
characteristics then is the same! How can a type
have the same characteristics (and name) and still be different?

long and int are different types since long can be longer than int,
even if in many implementations long == int. OK.

But char can never have a different size than one of the
signed/unsigned char types so IT IS the same...
This usually
doesn't matter due to implicit conversions, but these types:

char*
unsigned char*
signed char*

are all incompatible; values of these types cannot be assigned to each
other without a cast. If char were an alias for either signed char or
unsigned char, this would not be the case. (Does lcc-win32 get this
right?)

Dunno. Char is signed by default.

G

Guest

jacob said:

Mmmmm

" char is distinct from both signed char and unsigned char,
though it has the same characteristics as one of them" ...

I have some difficulty following you here. If it has the same
characteristics then is the same! How can a type
have the same characteristics (and name) and still be different?

#include <limits.h>

#if CHAR_MIN < 0
typedef signed char plain_char;
#else
typedef unsigned char plain_char;
#endif

plain_char *a;
/* really plain */ char *b;

int main(void) {
a = b; /* disallowed */
b = a; /* disallowed */
}

If char were the same type as (un)signed char, this would be allowed.

P

P.J. Plauger

Keith Thompson a écrit :

Mmmmm

" char is distinct from both signed char and unsigned char,
though it has the same characteristics as one of them" ...

I have some difficulty following you here. If it has the same
characteristics then is the same! How can a type
have the same characteristics (and name) and still be different?

The proper term, instead of "characteristics", is "representation".
It is often true in C that two types have the same representation
but are nevertheless considered by the compiler to be distinct
types. char/signed char or char/unsigned char is just one of these
pairs.
long and int are different types since long can be longer than int,
even if in many implementations long == int. OK.

But char can never have a different size than one of the
signed/unsigned char types so IT IS the same...

The same representation, yes.
Dunno. Char is signed by default.

Sez who?

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com

P

P.J. Plauger

P.J. Plauger a écrit :

Thanks for your answer Mr Plauger but I could not find that type
classification there. Maybe you would give a more specific link?
I browsed a lot of C stuff (and C++ stuff) but could not find it.

We don't include the language portion of P&B in our latest manual,
since it's a pure library manual as much as possible. But you'll
find descriptions of the constraints on:

-- wchar_t, size_t, ptrdiff_t, sig_atomic_t, wint_t, and the
<stdint.h> types

-- time_t, clock_t, wctrans_t, and wctype_t

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com

C

CBFalconer

Richard said:
.... snip ...

Not necessarily. For example, on historic implementations, time_t
was often larger than a single long, and was therefore a struct.
Ditto for, e.g., fpos_t. The point about such types is that they
may be one specific primitive type on any particular implementation,
but to the wise C programmer they must remain abstract types. As
such, they deserve discussion.

As far as I am concerned, a 'type' means specifying the domain of
allowable values, together with a set of operations on those
values. C arithmetical types are extremely primitive, in that they
cannot precisely specify the domain. They tend to simply specify a
maximum (and minimum) value, which is pre-defined. This is one of
the primary causes of invalid indices.

Even an enum cannot specify the precise validity range in C. You
can catch unenumerated values with a switch statement having a
default case.

C

CBFalconer

Eric said:
.... snip ...

The Standard disagrees with you (6.2.5/14). `char' is a type unto
itself, distinct from both `signed char' and `unsigned char'.
`int' and `short' are distinct types even when both are 16 bits
wide; `int' and `long' are distinct even when both are 32 bits
wide; `double' and `long double' are distinct even when both are
IEEE double-precision numbers. Representation and behavior are
not the sole ingredients of "type."

Reminds me of the arguments about type compatibility during Pascal
standardization. It eventually became identical type names, rather
than composition.

M

Mark McIntyre

As far as I understood this stuff, all those are defined in terms of
one of the primitive types in the enumeration above.
For instance, in many implementations size_t is unsigned long,
or time_t is long long, or clock_t is int, etc etc.

In fact the standard _doesn't_ say they have to be synonyms to any
other type.

For instance clock_t and time_t merely have to be arithmetic, so it
could be a a 2560-bit double (7.23), irrespective of whether a long
double were 32, 64, 80 or 128 bits. Size_t has to be an unsigned
integer type - but again there's no restriction on width (7.17) so it
could be wider than long long. In fact such designs might actually
make sense - using an integer type for time _is_ kinda daft, while
size_t needs to be able to refer to all possible availalbe memory..
The same applies to chart ("plain" char) since it is defined either
as unsigned or signed char, what means it is not another basic
type but a synonym for one of the char types.

The C standard does explicitly say that its a distinct type
(6.2.5p15).
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan

K

Keith Thompson

jacob navia said:
Keith Thompson a écrit :

Mmmmm

" char is distinct from both signed char and unsigned char,
though it has the same characteristics as one of them" ...

I have some difficulty following you here. If it has the same
characteristics then is the same!

Um, no.
How can a type
have the same characteristics (and name) and still be different?

By having the same characteristics (*not* the same name) and still
being different. What's unclear about that?
long and int are different types since long can be longer than int,
even if in many implementations long == int. OK.

Right, assuming that "long == int" is a shorthand for "long and int
have the same range and size".

int* and float* may very well have exactly the same characteristics
(representation, alignment, etc.), but they're distinct types.

long and int are distinct types even if they happen to have the same
properties. It's exactly the same for char and signed char, and for
char and unsigned char.
But char can never have a different size than one of the
signed/unsigned char types so IT IS the same...

No, they're distinct types (that happen to have the same size). Are
you arguing that size is the only thing that determines whether two
types are the same? It isn't.

C99 6.2.5p15:

The three types char, signed char, and unsigned char are
collectively called the _character types_. The implementation
shall define char to have the same range, representation, and
behavior as either signed char or unsigned char.

with a footnote:

CHAR_MIN, defined in <limits.h>, will have one of the values 0 or
SCHAR_MIN, and this can be used to distinguish the two
options. Irrespective of the choice made, char is a separate type
from the other two and is not compatible with either.
Dunno. Char is signed by default.

Try compiling this:

#include <limits.h>
int main(void)
{
char *cp;
unsigned char *up;
signed char *sp;

#if CHAR_MIN == 0
/* plain char is unsigned */
cp = up; /* constraint violation */
#else
/* plain char is signed */
cp = sp; /* constraint violation */
#endif
return 0;
}

A conforming compiler must issue a diagnostic for whichever assignment
is not deleted by the preprocessor. (If the diagnostic includes a
line number, it will tell you whether plain char is signed or
unsigned.) What does lcc-win32 do (in conforming mode)?

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.

Members online

No members online now.