当我处理特定数据类型时,我通常需要知道它在程序中占用的大小。最近我想到了通用解决方案,可以处理 C++ 语言中所有数据类型的这个问题,包括类型别名和用户定义的数据类型。
当我开始实现时,我意识到编写适用于所有平台的可移植程序并不容易,因为 C++ 中的数据类型实际上是编译器、体系结构和操作特定实体。
它主要是工作,但有一些我无法处理的边缘情况和一些我不确定的点。
程序简介:
程序使用Template Specialization来区分 基本数据类型。操作是编译时和决策机制 通过模板特化工作。问题在于,如果将两种类型推导为同一类型(包括类型别名),就会出现编译器错误。
一个简短的例子是:
“short”或“short int”或“signed short”可能都等同于编译器所感知的“short int”(当然这可能是特定于编译器的特性)。如果“short”和“short int”都提供给程序,模板专门化机制会提示其中一个已经被定义。
那么问题是:
例如,我如何确定类型“short”、“short int”或“signed short”是否会被推导为相同类型?有没有办法在编译时检查它?
类型别名的情况也是一样的,因为模板特化是通过它们的原始类型发生的。同样,如果同时提供了“short int”和“std::size_t”,并且“std::size_t”恰好被系统定义为“short int”,则程序无法编译,因为编译器会提示存在一个专门的模板。
我使用了以下 link以确保哪些类型彼此等效,但我怀疑并非所有编译器都遵循这些规则的实现。
我得到的输出。
bool : 1 bytes | 8 bits
char : 1 bytes | 8 bits
signed char : 1 bytes | 8 bits
unsigned char : 1 bytes | 8 bits
wchar_t : 4 bytes | 32 bits
char16_t : 2 bytes | 16 bits
char32_t : 4 bytes | 32 bits
short int : 2 bytes | 16 bits
unsigned short int : 2 bytes | 16 bits
int : 4 bytes | 32 bits
unsigned int : 4 bytes | 32 bits
long int : 8 bytes | 64 bits
unsigned long int : 8 bytes | 64 bits
long long int : 8 bytes | 64 bits
unsigned long long int : 8 bytes | 64 bits
float : 4 bytes | 32 bits
double : 8 bytes | 64 bits
long double : 16 bytes | 128 bits
nullptr_t : 8 bytes | 64 bits
Example : 168 bytes | 1344 bits
NULL macro is of integral type.
这在概念上是我需要的:
bool : 1 bytes | 8 bits
char : 1 bytes | 8 bits
signed char : 1 bytes | 8 bits
unsigned char : 1 bytes | 8 bits
wchar_t : 4 bytes | 32 bits
char16_t : 2 bytes | 16 bits
char32_t : 4 bytes | 32 bits
short int : 2 bytes | 16 bits
// -----------WHAT I NEED CONCEPTUALLY----------------
short : short is same as short int //This would be a compile-time error normally.
signed short int : signed short int is same as short int //This would also be a compiler time error.
std::size_t : std::size_t is of short int type. //Since "short int" is already defined, this is compile-time error as well.
//-----------------------------------------------------
unsigned short int : 2 bytes | 16 bits
int : 4 bytes | 32 bits
unsigned int : 4 bytes | 32 bits
long int : 8 bytes | 64 bits
unsigned long int : 8 bytes | 64 bits
long long int : 8 bytes | 64 bits
unsigned long long int : 8 bytes | 64 bits
float : 4 bytes | 32 bits
double : 8 bytes | 64 bits
long double : 16 bytes | 128 bits
nullptr_t : 8 bytes | 64 bits
Example : 168 bytes | 1344 bits
NULL macro is of integral type.
这是代码。
#ifndef TYPE_INFO_CPP
#define TYPE_INFO_CPP
#include <iostream>
#include <iomanip>
#include <type_traits>
/*
Just call:
SYS_CHECK();
In your main function
*/
//Types given into the template function as template parameters via macro
#define TYPES bool, \
char, \
signed char, \
unsigned char, \
wchar_t, \
char16_t, \
char32_t, \
short int, \
unsigned short int, \
int, \
unsigned int, \
long int, \
unsigned long int, \
long long int, \
unsigned long long int, \
float, \
double, \
long double, \
std::nullptr_t, \
Example
// std::size_t, \
// std::string::size_type
//Dummy Struct Declaration to enable Template Specialization
template <typename T>
struct TypeTraits;
//Template Specialization via macro
//Template Specialization is used to distinguish different types
#define REGISTER_TYPE(X) \
template <> \
struct TypeTraits <X> { \
static const char * name; \
}; \
const char * TypeTraits<X>::name = #X;
//To get rid of std:: prefix during console output
#define INTRODUCE_NULLPTR_T() \
using std::nullptr_t;
//Example User-Defined Type Body
struct Example {
char arr1[100];
int a;
double b;
char arr2[50];
};
//These macros are short-hand for declaring specialized templates of the dummy template declared above
REGISTER_TYPE(bool)
REGISTER_TYPE(char)
REGISTER_TYPE(signed char)
REGISTER_TYPE(unsigned char)
REGISTER_TYPE(wchar_t)
REGISTER_TYPE(char16_t)
REGISTER_TYPE(char32_t)
REGISTER_TYPE(short int)
REGISTER_TYPE(unsigned short int)
REGISTER_TYPE(int)
REGISTER_TYPE(unsigned int)
REGISTER_TYPE(long int)
REGISTER_TYPE(unsigned long int)
REGISTER_TYPE(long long int)
REGISTER_TYPE(unsigned long long int)
REGISTER_TYPE(float)
REGISTER_TYPE(double)
REGISTER_TYPE(long double)
//Example User-Defined Type
REGISTER_TYPE(Example)
INTRODUCE_NULLPTR_T()
REGISTER_TYPE(nullptr_t)
template <bool T = std::is_integral<decltype(NULL)>::value,
bool U = std::is_pointer<decltype(NULL)>::value,
bool Y = std::is_scalar<decltype(NULL)>::value>
void is_NULL_integral() {
std::cout << "NULL macro is of ";
if (T) {
std::cout << "integral";
}
else if (U) {
std::cout << "pointer";
}
else if(Y) {
std::cout << "nulltpr_t";
}
else {
std::cout << "neither pointer nor integral or scalar";
}
std::cout << " type." << std::endl;
}
template <typename T, short int byte = 8>
void convert_byte_to_bit() {
std::cout << " | ";
std::cout << byte * sizeof(T) << " bits" << std::endl;
}
template <typename T>
void _display_helper() {
std::cout << std::left << std::setw(23) << TypeTraits<T>::name << " : "
<< sizeof(T) << " bytes" << std::left;
convert_byte_to_bit<T>();
}
template <typename T>
void display_default_size() {
_display_helper<T>();
}
template <typename T, typename U, typename ... Args>
void display_default_size() {
_display_helper<T>();
display_default_size<U, Args...>();
}
void SYS_CHECK() {
display_default_size<TYPES>();
std::cout << std::endl;
is_NULL_integral();
}
#endif
最佳答案
How can I make sure, for example, whether types "short", "short int" or "signed short" will be deduced to the same type or not? Is there a way to check that at compile-time?
您已将您的问题标记为 C++11,所以...这是针对类型特征的工作; std::is_same
。
它在编译时工作。
举例
#include <type_traits>
#include <iostream>
int main()
{
constexpr bool b1 { std::is_same<short, short int>::value };
constexpr bool b2 { std::is_same<short, signed short int>::value };
constexpr bool b3 { std::is_same<short, unsigned short int>::value };
std::cout << b1 << std::endl; // print 1
std::cout << b2 << std::endl; // print 1
std::cout << b3 << std::endl; // print 0
}
En passant: short
和 short int
是 signed short int
的别名
--- 编辑 ---
OP 询问
Is there any mention in C++11 standard which states "short" and "short int" are indeed are alias for "signed short int"? Is there any resource I can use for looking up other fundamentals types as well?
我不知道标准在哪里提到它,但它是从旧 C 开始的一个基本方面;你已经链接了一个很棒的(恕我直言)资源;在您链接的页面(this page)中,您可以阅读
- “如果使用下面列出的任何修饰符,则可以省略关键字 int”,
签名
“如果省略则为默认值”- 并且“对于所有类型说明符,任何顺序都是允许的”。
因此(通过示例)signed short int
、short signed int
、short int signed
、signed int short
、int signed short
、int short signed
、signed short
、short signed
和short
code> 是同一类型的别名。
关于c++ - 在 C++ 中显示所有基本类型的数据大小的程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41090782/