tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Avoiding #define uint8_t (and similar) in stdint.h



On Thu, Dec 18, 2014 at 09:22:16PM +0100, Martin Husemann wrote:
 > I think I have discussed this issue with some folks here (apb? christos?)
 > some time ago, but I can't find any traces of the discussion right now -
 > so let me try to start from scratch:
 > 
 > We have this strange construct in <stdint.h>:
 > 
 > #ifndef uint8_t
 > typedef __uint8_t       uint8_t;
 > #define uint8_t         __uint8_t
 > #endif
 > 
 > ... and repeat for all other types.

The purpose of this is to avoid issuing the typedef more than once for
types that can be defined by more than one standard header file.

This is a newish idiom; the older idiom is

   #ifdef  _BSD_SIZE_T_
   typedef _BSD_SIZE_T_ size_t;
   #undef  _BSD_SIZE_T_
   #endif

and can still be seen with e.g. size_t and others because no complete
conversion was ever done.

If the new form doesn't work, the least intrusive change is to go back
to the old one. However, it isn't fully general because there are a
few cases where headers need to use types they're not allowed to
expose, and that #undef makes it unsafe to use either _BSD_SIZE_T_ or
size_t in such contexts.

The right way is to typedef everything with __ in one header that can
be included everywhere (like machine/ansi.h is) and then place
additional conditional typedefs where needed. The problem with the
idiom originally cited is that it uses the exposed type name itself as
the guard ifdef, which I've always thought untidy. Using some other
symbol instead is safe:

  #ifndef __did_uint8_t
  typedef __uint8_t       uint8_t;
  #define __did_uint8_t

although since as far as I know all the sized types go together, you
can do

  #ifndef __did_sized_types
  typedef __uint8_t       uint8_t;
  typedef __uint16_t      uint16_t;
  typedef __uint32_t      uint32_t;
  typedef __uint64_t      uint64_t;
  #define __did_sized_types

and IMO the best way to do this is to take these typedefs and put them
in their own header file (e.g. types/sized.h) using standard include
protection:

  #ifndef _TYPES_SIZED_H_
  typedef __uint8_t       uint8_t;
  typedef __uint16_t      uint16_t;
  typedef __uint32_t      uint32_t;
  typedef __uint64_t      uint64_t;
  #define _TYPES_SIZED_H_

Then this file can be included where these types are supposed to be
exposed.

One can make a mess with this if one isn't careful (it's a good idea
to keep all these headers in their own directory) and it will be
particularly fun in NetBSD since we don't have a clean separation of
user and kernel headers. Otherwise a lot of this can be avoided by
e.g. having <sys/types.h> just include <stdint.h> instead of having to
share pieces with it.

 > I can not recall why we do the double bounce, but one way to avoid the
 > different names would be:
 > 
 > #define uint8_t uint8_t
 > 
 > IIRC special macro expansion rules make this a valid construct and
 > it probably can not break valid C++ code.

Using something like __did_uint8_t would be safer and tidier.

 > Another option would be to remove the #ifdef dance alltogether and just risk
 > duplicate (but identical) typedefs, using the compiler predefined defines:
 > 
 > typedef __UINT8_TYPE__ uint8_t;

This is illegal, regardless of whether gcc's decided to silently
accept it.

 > I would go for the second options. What do others think? Should we get this
 > fixed now and pull up to -7 in time?

I'm not sure this kind of thing ought to be pulled up, but I'm not releng.

-- 
David A. Holland
dholland%netbsd.org@localhost


Home | Main Index | Thread Index | Old Index