cstdint vs stdint.h
The original intention in C++98 was that you should use <cstdint>
in C++, to avoid polluting the global namespace (well, not <cstdint>
in particular, that's only added in C++11, but the <c*>
headers in general).
However, implementations persisted in putting the symbols into the global namespace anyway, and C++11 ratified this practice[*]. So, you basically have three options:
- Use
<cstdint>
and either fully qualify each integer type you use or else bring it into scope withusing std::int32_t;
etc (annoying because verbose, but it's the right way to do it just like for any other symbol in the C++ standard library) - Use
<stdint.h>
(slightly bad because deprecated) - Use
<cstdint>
and assume your implementation will put the symbols in the global namespace (very bad because not guaranteed).
In practice I suspect that an annoying large amount of code uses the last option, simply because it's easy to do by accident on an implementation where <cstdint>
puts the symbols in the global namespace. You should try to use the first. The second has one virtue, that it is guaranteed to put stuff in the global namespace instead of only maybe doing it. I don't think that's particularly useful, but it might save some typing if that's your priority.
There's a fourth option, #include <cstdint>
followed by using namespace std;
which is sometimes useful but there are places that you shouldn't put the using namespace std;
. Different people will have different ideas where those places are, but "at top level in a header file" is worse than "at top level in a cpp file", which is worse than "in a limited scope". Some people never write using namespace std;
at all.
[*] That means C++ standard headers are permitted to put stuff in the global namespace but not required to. So you have to avoid colliding with those symbols, but you can't actually use them because they might not be there. Basically, the global namespace in C++ is a minefield, try to avoid it. One might argue that the committee has ratified a practice by implementations that is nearly as harmful as sticking using namespace std;
at top level in a header file -- the difference being that the implementations only do it for symbols in the C standard library, whereas using namespace std;
does it for C++-only symbols too. There's a section in the C standard that lists names reserved for future additions to the standard. It's not a completely stupid idea to treat those names as reserved in the C++ global namespace too, but it's not essential.
stdint.h or standard types?
First off, Microsoft's implementation does support <stdint.h>
.
Use the appropriate type for what you're doing.
If you need, for example, an unsigned type that's exactly 16 bits wide with no padding bits, use uint16_t
, defined in <stdint.h>
.
If you need an unsigned type that's at least 16 bits wide, you can use uint_least16_t
, or uint_fast16_t
, or short
, or int
.
You probably don't need exact-width types as often as you think you do. Very often what matters is not the exact size of a type, but the range of values it supports. But exact representation is important when you're interfacing to some externally defined data format. In that case, you should already have declarations that tell you what types to use.
There are specific requirements on the ranges of the predefined types: char
is at least 8 bits, short
and int
are at least 16 bits, long
is at least 32 bits, and long long
is at least 64 bits. Also, short
is at least as wide as char
, int
is at least as wide as short
, and so forth. (The standard specifies minimum ranges, but the minimum sizes can be derived from the ranges and the fact that a binary representation is required.)
Note that <stdint.h>
is a C header. If you #include
it in a C++ program, the type names will be imported directly into the global namespace, and may or may not also be imported into the std
namespace. If you #include <cstdint>
, then the type names will be imported into the std
namespace, and may or may not also be imported into the global namespace. Macro names such as UINT32_MAX
are not in any namespace; they're always global. You can use either version of the header; just be consistent about using or not using the std::
prefix.
Is there a reason to use std::int64_t from cstdint / cinttypes over int64_t from stdint.h / inttypes.h ?
In C++, the "C library" headers of the form <foo.h>
are deprecated, and headers <cfoo>
should be used instead. (I put "C library" in quotes because that's just a name for this part of the C++ standard library. Everything we're talking about is part of the C++ standard library, nothing has actually to do with C.)
Whether you should use the non-deprecated headers depends on your personal attitude towards deprecation.
(The amount of physical typing the code author has to do is a very poor concern. Code is read and maintained far more than it is written. The latter are important concerns, the former mostly a distraction.)
Use types in cstdint with or without namespace
Prefer names declared in the std
namespace. The reason is given in §17.6.1.3/4 (ISO/IEC 14882:2011(E), C++11):
Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name
.h
, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespacestd
. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespacestd
by explicit using-declarations (7.3.3).
If you use the names from the <c
name>
headers without std
, your program is relying on unspecified requirements.
This was different in C++03 and earlier where names were only supposed to appear in the std
namespace. However, the reality was that many implementations were simply injecting the contents of the C standard library headers <
name.h>
into std
and so this was accommodated for in C++11. The corresponding section (§17.4.1.2/4) from the C++03 standard says:
Except as noted in clauses 18 through 27, the contents of each header cname shall be the same as that of the corresponding header name
.h
, as specified in ISO/IEC 9899:1990 Programming Languages C (Clause 7), or ISO/IEC:1990 Programming Languages—C AMENDMENT 1: C Integrity, (Clause 7), as appropriate, as if by inclusion. In the C++ Standard Library, however, the declarations and definitions (except for names which are defined as macros in C) are within namespace scope (3.3.5) of the namespacestd
.
Further to this, qualifying names with std::
helps to avoid collisions - you know exactly what you're getting if you fully qualify it. If you're really going to do using namespace std
or using std::something
, at least do it in as minimal a scope as you can.
Why do stdint.h can be found but cstdint not?
Your compiler supports the old C++ standard which has no <cstdint>
(as C90 had no <stdint.h>
). <cstdint>
is new to C++11.
difference between stdint.h and inttypes.h
See the wikipedia article for inttypes.h.
Use stdint.h for a minimal set of definitions; use inttypes.h if you also need portable support for these in printf, scanf, et al.
Calling C++ standard header (cstdint) from C file
The c
prefix in cstdint
is because it's really a header file incorporated from C. The name in C is stdint.h
.
You need to conditionally include the correct header by detecting the __cplusplus
macro. You also need this macro to use the extern "C"
part, as that's C++ specific:
#ifndef OUTPUT_FROM_CPP_H
#define OUTPUT_FROM_CPP_H
#ifdef __cplusplus
// Building with a C++ compiler
# include <cstdint>
extern "C" {
#else
// Building with a C compiler
# include <stdint.h>
#endif
uint8_t myCppFunction(uint8_t n);
#ifdef __cplusplus
} // Match extern "C"
#endif
#endif
cstdint vs std::size_t types
The C++11 standard (section 18.2) says:
(5). The type
ptrdiff_t
is an implementation-defined signed integer type that can hold the difference of two subscripts in an array object....(6). The type
size_t
is an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object.(7). [Note: It is recommended that implementations choose types for
ptrdiff_t
andsize_t
whose integer conversion ranks (4.13) are no greater than that ofsigned long int
unless a larger size is necessary to contain all the possible values. —end note]
From this we see that:
size_t
is specifically for byte-sizes of objects, and its companion ptrdiff_t
is specifically for math with array indices. uintmax_t
, on the other hand, is the largest unsigned integral type.
Depending on the platform uintmax_t
could be larger than size_t
.
We also know that:
sizeof
returns a size_t
, and the STL container size_type
s are typically identical to size_t
, so it makes sense to use size_t
in code that deals with sizeof
or STL containers.
Now mix in the fact the <cstdint>
is new-ish to C++, and I think it's pretty clear why established libraries like Boost have been using size_t
.
c++ std:: types instead of corresponding c types
So is there a need to use say std::int8_t instead of the short C form int8_t somewhere?
Yes. Per [headers]/4 it is unspecified if the C names are defined in the global namespace or not. Because of this you need std::int8_t
to use int8_t
. It doesn't guarantee that std::int8_t
exists, just that if it does exist, using std::int8_t
is guaranteed to work.
You can just add using std::int8_t;
so you don't have to type std::int8_t
all over the place.
The relevant part of [headers]/4 is
In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope of the namespace std
emphasis mine
This means we know they are declared in std::
. The part
It is unspecified whether these names (including any overloads added in [language.support] through [thread] and [depr]) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations ([namespace.udecl]).
then allows the names to be in the global namespace, but does required it. This lets implementations do things like
<cstdint>
:
namespace std
{
#include <stdint.h>
}
or
<cstdint>
:
#include <stdint.h>
namespace std
{
using ::int8_t;
using ::int16_t;
//...
}
Bot accomplish the same thing (putting the names in std::
) and are legal implementations but only the second one puts the names in the global scope.
Related Topics
Linker Error When Calling a C Function from C++ Code in Different VS2010 Project
Difference Between C++03 Throw() Specifier C++11 Noexcept
C++11: How to Alias a Function
Why Can't Static_Cast Be Used to Down-Cast When Virtual Inheritance Is Involved
Sendinput() Not Equal to Pressing Key Manually on Keyboard in C++
How to Store Extremely Large Numbers
Comparison of Double, Long Double, Float and Float128
Error: Invalid Operands of Types 'Const Char [35]' and 'Const Char [2]' to Binary 'Operator+'
How to Actually Implement the Rule of Five
Force C++ Structure to Pack Tightly
Why Are Memcpy() and Memmove() Faster Than Pointer Increments
Performance of Qsort VS Std::Sort
How to Find the Size of an Int[]
C++ Compiler Error C2280 "Attempting to Reference a Deleted Function" in Visual Studio 2013 and 2015