Suitable type names needed for portable integers

J

James Harris

James Kuyper said:
The <stdint.h> header that was added in C99 provides three pairs of
families of type names: intN_t, int_leastN_t, and int_fastN_t.


Yes, I'm a little confused actually. <stdint.h> is the obvious choice,
and I'm wondering why OP isn't just using it.


His target systems include ones where C99 is not supported. Of course,
many of those systems support <stdint.h>, or some variant thereof, as a
C90 extension. Even on the ones that don't, it would be feasible to
provide your own, and there exist well-know versions in the public
domain. However, these points have been made to him, and don't seem to
have affected his thinking.


[OP] My thinking has been helped a lot by the recommendations people have
given. It's reasonble, though, not to feel obliged to do everything that
everyone advises.

To get 16-bit C compiles on Unix (which are not well supported) I have been
using bcc. It does not provide stdint.h.

I recently found a version of Open Watcom 16-bit compiler that would install
on Linux. That may provide a way to avoid some of the limitations of bcc.
The masochist in me, however, also thinks it could provide a good
alternative. Open Watcom will compile to large and compact models where bcc
only supports the tiny model. So I might just keep both. The differences
would be useful.
The fundamental problem, I think, is that he doesn't trust the C
compiler or <stdint.h> to have made what he considers to be the correct
choice. Using C necessarily involves giving up a certain amount of
control over the generated code, compared to assembly language. That's
part of what makes it a higher-level language. It's very low-level for a
high-level language, but it is still, definitely, a high-level language,
at least by comparison with assembler.

Not quite. I would normally trust stdint.h. I don't fully trust bcc and with
good reason. I found the other day that its realloc fails to copy the last
two bytes on some realloc calls. That's not a criticism of bcc per se. It is
free and known to be limited. But it illustrates why it's not always wise to
give carte blanche to a compiler.
I've seen such attitudes before, both in people moving to C from
assembler, and in C programmers who are temperamentally better suited to
being assembly language programmers than C programmers. The first group
needs to learn to let go and let C do its thing. The second group needs
to switch to some other language better suited to their temperaments.

There's possibly some truth in that character assessment. However, I also
choose to write a lot in Python which is much higher level than C. I'd like
to think I use the right tool for the job in hand.

For the piece of work I have in progress, low-level programming is needed.
It's as simple as that.

James
 
J

jadill33

I am working on code that is to run on 16-bit, 32-bit and 64-bit machines
and am looking for a way to declare specific types of integers. Could you
suggest suitable names for the following?

1. Integers which will be 16-bit on 16-bit machines and 32-bit on both
32-bit machines and 64-bit machines.

2. Integers which will be 16-bit on 16-bit machines, 32-bit on 32-bit
machines and 64-bit on 64-bit machines.

Both of these types need at least signed and unsigned variants so the need
is for exactly four type names:

a name for signed 16, 32, 32
a name for unsigned 16, 32, 32

a name for signed 16, 32, 64
a name for unsigned 16, 32, 64

I intend to define these names explicitly so that they are not subject to
the defaults of any given compiler. So I don't want to use int, for example.
I was going to use sint and uint as two of the names but one compiler
predefines uint ... which is a pain. So I am looking for something else. All
that's needed are four names. Any suggestions? Any precedent?

There's no precedent that I'm familiar with, but I have run into this kind
of situation before. In my scenario, I have a time library that needs to
handle fractional seconds similar to 'struct timeval', but with the option
of using a 64-bit second count when 64-bit integers are available, but
revert down to use 32-bit integers if 64-bit is not available.

\code
/* The 'intmax64_t' type prefers to use a 64-bit signed integer type,
but defers to 'long int' if no 64-bit integer type is available. */
#if defined(INT64_MAX)
typedef int64_t intmax64_t;
typedef uint64_t uintmax64_t;
#else
typedef long int intmax64_t;
typedef unsigned long uintmax64_t;
#endif

#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)

/* The 'intmax64_t' and 'uintmax64_t' limits depend on whether
INT64_MAX or UINT64_MAX are available. */
#if defined(INT64_MAX)
# define INTMAX64_MIN INT64_MIN
# define INTMAX64_MAX INT64_MAX
# define UINTMAX64_MAX UINT64_MAX
#else
# define INTMAX64_MIN LONG_MIN
# define INTMAX64_MAX LONG_MAX
# define UINTMAX64_MAX ULONG_MAX
#endif

#endif /* !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) */

/* 7.18.4 Macros for integer constants. */
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)

#if defined(INT64_MAX)
# define INTMAX64_C(v) INT64_C(v)
# define UINTMAX64_C(v) UINT64_C(v)
#else
# define INTMAX64_C(v) v ## L
# define UINTMAX64_C(v) v ## UL
#endif

#endif /* !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) */

/* 7.8.1 Macros for format specifiers */
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)

/* The 'intmax64_t' fprintf macro modifiers. */
#if defined(__STDC__) && defined(__STDC_VERSION__)
# if (__STDC__ && __STDC_VERSION__ >= 199901L)
# define inttypes_pridmax64_defined
# define PRIdMAX64 PRId64
# define PRIiMAX64 PRIi64
# endif
#endif

#if !defined(inttypes_pridmax64_defined) && !defined(ANSI_C_PSTDINT)
# if defined(INT64_MAX) && (INTMAX64_MAX == INT64_MAX)
# define inttypes_pridmax64_defined
# define PRIdMAX64 PRId64
# define PRIiMAX64 PRIi64
# endif
#endif

#if !defined(inttypes_pridmax64_defined)
# define PRIdMAX64 "ld"
# define PRIiMAX64 "li"
#endif

/* The 'uintmax64_t' fprintf macro modifiers. */
#if defined(__STDC__) && defined(__STDC_VERSION__)
# if (__STDC__ && __STDC_VERSION__ >= 199901L)
# define inttypes_priumax64_defined
# define PRIoMAX64 PRIo64
# define PRIuMAX64 PRIu64
# define PRIxMAX64 PRIx64
# define PRIXMAX64 PRIX64
# endif
#endif

#if !defined(inttypes_priumax64_defined) && !defined(ANSI_C_PSTDINT)
# if defined(UINT64_MAX) && (UINTMAX64_MAX == UINT64_MAX)
# define inttypes_priumax64_defined
# define PRIoMAX64 PRIo64
# define PRIuMAX64 PRIu64
# define PRIxMAX64 PRIx64
# define PRIXMAX64 PRIX64
# endif
#endif

#if !defined(inttypes_priumax64_defined)
# define PRIoMAX64 "lo"
# define PRIuMAX64 "lu"
# define PRIxMAX64 "lx"
# define PRIXMAX64 "lX"
#endif

#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */
\endcode

You can make a similar template for intmax32_t and uintmax32_t. Hopefully
it should be enough to conjure up something that can work for you. If you
have systems that don't support 'long int', you may have to do some tweaking
and comparisons with integer type limits.

If you need your own <stdint.h> wrapper, Mr. Waltman gave a couple of
examples you could work with.

Best regards,
John D.
 
J

James Kuyper

On 08/20/2013 03:16 PM, (e-mail address removed) wrote:
....
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) ....
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) ....
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)

None of those identifiers starting with __STDC_ is defined by the C
standard. "All identifiers that begin with an underscore and ... another
underscore are always reserved for any use." (7.1.3p1), so you shouldn't
be defining them. The C++ standard says essentially the same thing
(17.6.4.3.2p1).
"Macros names starting with _ _STDC_ are reserved for future
standardization." (6.11.9), so the implementation of C that you're using
shouldn't be defining them, either.

The latest draft of the C++ standard that I have access to is n3690.pdf,
dated . In section 18.4.1p2, it claims that footnotes 219, 220, and 222
of the C standard mention __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS
above. Section 27.9.2p3 claims that footnote 182 of the C standard
refers to __STDC_FORMAT_MACROS. The C++ standard mentions these for the
sole purpose of specifying that they play no role in C++.

I have n1570.pdf, which is almost identical to the final C2011 standard;
it mentions none of those macros. Since I'm comparing two draft
standards, rather than final standards, I can't be sure whether either
of them is right - but they cannot both be right. Can anyone explain
this discrepancy?

If the final C standard does mention those macros, but does so only in
footnotes, nothing it could say about them would be normative, so
sections 7.1.3p1 and 17.6.4.3.2p1 would still apply.
 
K

Keith Thompson

James Kuyper said:
On 08/20/2013 03:16 PM, (e-mail address removed) wrote:
...

None of those identifiers starting with __STDC_ is defined by the C
standard. "All identifiers that begin with an underscore and ... another
underscore are always reserved for any use." (7.1.3p1), so you shouldn't
be defining them. The C++ standard says essentially the same thing
(17.6.4.3.2p1).
"Macros names starting with _ _STDC_ are reserved for future
standardization." (6.11.9), so the implementation of C that you're using
shouldn't be defining them, either.

The latest draft of the C++ standard that I have access to is n3690.pdf,
dated . In section 18.4.1p2, it claims that footnotes 219, 220, and 222
of the C standard mention __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS
above. Section 27.9.2p3 claims that footnote 182 of the C standard
refers to __STDC_FORMAT_MACROS. The C++ standard mentions these for the
sole purpose of specifying that they play no role in C++.

I have n1570.pdf, which is almost identical to the final C2011 standard;
it mentions none of those macros. Since I'm comparing two draft
standards, rather than final standards, I can't be sure whether either
of them is right - but they cannot both be right. Can anyone explain
this discrepancy?

If the final C standard does mention those macros, but does so only in
footnotes, nothing it could say about them would be normative, so
sections 7.1.3p1 and 17.6.4.3.2p1 would still apply.

The released 2011 C++ standard refers to the 1999 C standard. (I have
copies of both.)

The 1999 ISO C standard has the following footnotes:

217) C++ implementations should define these macros only when
__STDC_LIMIT_MACROS is defined before <stdint.h> is included.
(referring to the limits for specified-width types)

218) C++ implementations should define these macros only when
__STDC_LIMIT_MACROS is defined before <stdint.h> is included.
(referring to limits of other types, PTR_DIFF_MIN et al)

220) C++ implementations should define these macros only when
__STDC_CONSTANT_MACROS is defined before <stdint.h> is included.
(referring to macros for integer constants, INT8_C() et al).

The 2011 C++ standard says, in 18.4.1 [cstdint.syn] paragraph 2,
discussing the <cstdint> header (C++'s version of <stdint.h>):

The header defines all functions, types, and macros the
same as 7.18 in the C standard. [ Note: The macros defined
by <cstdint> are provided unconditionally. In particular,
the symbols __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS
(mentioned in footnotes 219, 220, and 222 in the C standard)
play no role in C++. — end note ]

Apparently the C committee made a recommendation in 1999 about
how C++ should handle those macros, and 12 years later the C++
committee didn't take their advice.

C++11 was the first C++ standard that referred to C99; the 2003
standard referred to C90 (plus the 1995 amendment).

(There are plans for a minor revision in 2014 and a major one in 2017.)
 
J

jadill33

On 08/20/2013 03:16 PM, (e-mail address removed) wrote:

...

None of those identifiers starting with __STDC_ is defined by the C
standard. "All identifiers that begin with an underscore and ... another
underscore are always reserved for any use." (7.1.3p1), so you shouldn't
be defining them. The C++ standard says essentially the same thing
(17.6.4.3.2p1).

"Macros names starting with _ _STDC_ are reserved for future
standardization." (6.11.9), so the implementation of C that you're using
shouldn't be defining them, either.

The latest draft of the C++ standard that I have access to is n3690.pdf,
dated . In section 18.4.1p2, it claims that footnotes 219, 220, and 222
of the C standard mention __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS
above. Section 27.9.2p3 claims that footnote 182 of the C standard
refers to __STDC_FORMAT_MACROS. The C++ standard mentions these for the
sole purpose of specifying that they play no role in C++.

I have n1570.pdf, which is almost identical to the final C2011 standard;
it mentions none of those macros. Since I'm comparing two draft
standards, rather than final standards, I can't be sure whether either
of them is right - but they cannot both be right. Can anyone explain
this discrepancy?

If the final C standard does mention those macros, but does so only in
footnotes, nothing it could say about them would be normative, so
sections 7.1.3p1 and 17.6.4.3.2p1 would still apply.

It's been a couple of years since I was working on this, but if I remember
correctly, I was looking at MinGW's version of <stdint.h> and <inttypes.h>
and copied the style used in their source file. It never donned on me at
the time that the macros themselves weren't standard C. The n1256.pdf that
I have does reference __STDC_FORMAT_MACROS and friends, but didn't realize
the new C standard took those footnotes out.

From a pure C standpoint, I will drop those references to those macros.
I probably shouldn't use reserved PRI macro identifiers either from
<inttypes.h>, but I can't bring myself to make up an arbitrary naming
convention when a good one already exists (I'll just have to live with
any future fallout).

Best regards,
John D.
 
M

Malcolm McLean

On 08/19/2013 04:44 PM, Edward A. Falk wrote:

The fundamental problem, I think, is that he doesn't trust the C
compiler or <stdint.h> to have made what he considers to be the correct
choice. Using C necessarily involves giving up a certain amount of
control over the generated code, compared to assembly language.
That's not the real problem.
The problem is that updating the standard means changing the standard, which
almost always breaks code.
So K and R didn't provide an isnan() or generate_nan() function. It's trivial
enough to write them, though generate_nan() has to crash out with an error
message on some hardware.
But once someone modifies the standard to support isnan(), then if you use
their isnan() your code won't run on any compiler that isn't up to date,
and if you write your own isnan(), you'll get lots of conflicts, unless
ypu mess up the code with #ifdefs.
So the real answer is to write uggle_isnan() and uggle_generatenan(),
which are unlikely to clash with any other names. The code then works
on all compilers except those that don't have nans, but that's kind of
inherent).
 
J

jadill33

On 08/19/2013 04:44 PM, Edward A. Falk wrote:
[snip]
So the real answer is to write uggle_isnan() and uggle_generatenan(),
which are unlikely to clash with any other names. The code then works
on all compilers except those that don't have nans, but that's kind of
inherent).

While that works in the pragmatic sense, and is a good idea in the library
API sense, applying the idea to standardized functions and types results in
a proliferation of definitions that make integration of code using multiple
libraries quite annoying.

Just consider all the naming conventions of typedef'd integers encountered
over the years. I grow tired of using an external library's version of
PREFIX_INT32 as a replacement for int32_t. I'd much prefer writing a
standard wrapper (in the scenario of supporting an older compiler) just to
keep the standard nomenclature rather than defining yet another arbitrary
naming convention, even with all the #ifdef warts. Ideally, the users
shouldn't be exposed to reading all the #ifdef junk anyways as long as a
documentation system (like doxygen) is used.

Best regards,
John D.
 
K

Keith Thompson

Keith Thompson said:
James Kuyper said:
On 08/20/2013 03:16 PM, (e-mail address removed) wrote:
...

None of those identifiers starting with __STDC_ is defined by the C
standard. "All identifiers that begin with an underscore and ... another
underscore are always reserved for any use." (7.1.3p1), so you shouldn't
be defining them. The C++ standard says essentially the same thing
(17.6.4.3.2p1).
"Macros names starting with _ _STDC_ are reserved for future
standardization." (6.11.9), so the implementation of C that you're using
shouldn't be defining them, either.

The latest draft of the C++ standard that I have access to is n3690.pdf,
dated . In section 18.4.1p2, it claims that footnotes 219, 220, and 222
of the C standard mention __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS
above. Section 27.9.2p3 claims that footnote 182 of the C standard
refers to __STDC_FORMAT_MACROS. The C++ standard mentions these for the
sole purpose of specifying that they play no role in C++.

I have n1570.pdf, which is almost identical to the final C2011 standard;
it mentions none of those macros. Since I'm comparing two draft
standards, rather than final standards, I can't be sure whether either
of them is right - but they cannot both be right. Can anyone explain
this discrepancy?

If the final C standard does mention those macros, but does so only in
footnotes, nothing it could say about them would be normative, so
sections 7.1.3p1 and 17.6.4.3.2p1 would still apply.

The released 2011 C++ standard refers to the 1999 C standard. (I have
copies of both.)

The 1999 ISO C standard has the following footnotes:

217) C++ implementations should define these macros only when
__STDC_LIMIT_MACROS is defined before <stdint.h> is included.
(referring to the limits for specified-width types)

218) C++ implementations should define these macros only when
__STDC_LIMIT_MACROS is defined before <stdint.h> is included.
(referring to limits of other types, PTR_DIFF_MIN et al)

220) C++ implementations should define these macros only when
__STDC_CONSTANT_MACROS is defined before <stdint.h> is included.
(referring to macros for integer constants, INT8_C() et al).

The 2011 C++ standard says, in 18.4.1 [cstdint.syn] paragraph 2,
discussing the <cstdint> header (C++'s version of <stdint.h>):

The header defines all functions, types, and macros the
same as 7.18 in the C standard. [ Note: The macros defined
by <cstdint> are provided unconditionally. In particular,
the symbols __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS
(mentioned in footnotes 219, 220, and 222 in the C standard)
play no role in C++. — end note ]

Apparently the C committee made a recommendation in 1999 about
how C++ should handle those macros, and 12 years later the C++
committee didn't take their advice.

C++11 was the first C++ standard that referred to C99; the 2003
standard referred to C90 (plus the 1995 amendment).

(There are plans for a minor revision in 2014 and a major one in 2017.)

And as you mentioned, James, the C11 standard (at least as of the N1570
draft) dropped those footnotes.

Note that __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS were intended
to be defined by the (C++) programmer, not by the implementation;
<stdint.h> or <cstdint> was intended to test whether they were defined.
 
T

Tim Rentsch

James Harris said:
I am working on code that is to run on 16-bit, 32-bit and 64-bit
machines and am looking for a way to declare specific types of
integers. Could you suggest suitable names for the following?

1. Integers which will be 16-bit on 16-bit machines and 32-bit on
both 32-bit machines and 64-bit machines.

2. Integers which will be 16-bit on 16-bit machines, 32-bit on
32-bit machines and 64-bit on 64-bit machines.

Both of these types need at least signed and unsigned variants so
the need is for exactly four type names:

a name for signed 16, 32, 32
a name for unsigned 16, 32, 32

a name for signed 16, 32, 64
a name for unsigned 16, 32, 64

I intend to define these names explicitly so that they are not
subject to the defaults of any given compiler. So I don't want to
use int, for example. I was going to use sint and uint as two of
the names but one compiler predefines uint ... which is a pain. So
I am looking for something else. All that's needed are four names.
Any suggestions? Any precedent?

Pick a simple starting point and run with it. The
main restriction on the starting point is that it
should allow easy change in names later should you
change your mind.

Example: type names Sx32, Ux32, Sx64, Ux64, with the
obvious meanings. These names are both sufficiently
suggestive and also likely to be unusual enough to be
easy to change later on. If you start using them and
don't mind them, keep using them. If you start using
them and find down the road you can't stand them, at that
point come up with something better and change them.
Repeat as necessary.
 
J

James Harris

....
It's been a couple of years since I was working on this, but if I remember
correctly, I was looking at MinGW's version of <stdint.h> and <inttypes.h>
and copied the style used in their source file. It never donned on me at
the time that the macros themselves weren't standard C. The n1256.pdf
that
I have does reference __STDC_FORMAT_MACROS and friends, but didn't realize
the new C standard took those footnotes out.

FWIW I wrote a header which is similar in principle to your set of
definitions. In my case, though, I did choose a completely distinct set of
names. Using separate names has some advantages, IMHO,

* no chance of clashing with names in a standard header (which is important
as I am compiling under a number of compilers most of which have the
standard header but not all),

* because the names are more distinct there's less chance of putting in a
standard name by mistake

* assures that the definitions are explicit and mine in all cases (whereas
where you define names #ifndef (std name) the definition could be the
inbuilt one and could be your own).

It does mean that I need to define every symbol and every print format that
I am going to use but I would have to do that even if wrapping them in a
#ifndef.
From a pure C standpoint, I will drop those references to those macros.
I probably shouldn't use reserved PRI macro identifiers either from
<inttypes.h>, but I can't bring myself to make up an arbitrary naming
convention when a good one already exists (I'll just have to live with
any future fallout).


Re. the print format names I currently have (though may change it) an
_FMT_DEC suffix. So where the type name is ui32 (unsigned int 32) the print
format for decimal is ui32_FMT_DEC (though I know the standard names include
a separate set for scanning).

James
 

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,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top