C与C++的数据类型

《Hands-On System Programming with C++》读书笔记之三

探索C/C++默认数据类型

字符类

  • char:通常但不总是8bits, corresponding with the ASCII, 编译器区别对待它和一般整型。
#include <iostream>
int main(void)
{
	int i = 0x42;
	char c = 0x42;
	const char *str = "Hello World\n";
	std::cout << i << '\n'; // 66
	std::cout << c << '\n'; // B
	std::cout << str; // Hello World
}

可以用下面的代码查看系统的数据类型长度。

#include <iostream>
#include <limits>

int main(void)
{
    using namespace std;
    auto num_bytes_signed = sizeof(signed char);
    auto min_singed = numeric_limits<signed char>().min();
    auto max_signed = numeric_limits<signed char>().max();

    auto num_bytes_unsigned = sizeof(unsigned char);
    auto min_unsigned = numeric_limits<unsigned char>().min();
    auto max_unsigned = numeric_limits<unsigned char>().max();

    cout << "num bytes(signed):" << num_bytes_signed << endl; // 1
    cout << "min value(signed):" << +min_singed << endl; // -128
    cout << "max value(signed):" << +max_signed << endl << endl; // 127
    cout << "num bytes(unsigned):" << num_bytes_unsigned << endl; // 1
    cout << "min value(unsigned):" << +min_unsigned << endl; // 0
    cout << "max value(unsigned):" << +max_unsigned << endl << endl; // 255
}
  • wchar_t: Unicode characters. 使用前务必确定数据的格式,我的系统里是4bytes。

整数类

  • short int: 我的系统中占用2 bytes。在大多数32或64位系统里,短于32位的操作数并不能提供效率,尤其是RISC指令集的CPU可能会需要额外很多指令来处理短操作数,因此需要小心使用。
  • int:我的系统中占用4 bytes。在64位处理器中int仍更多保持32位是出于兼容性的考虑。
  • long int:我的系统中占用8 bytes, (Windows中为4bytes,long long int才是8bytes)。

浮点数类

浮点数类型在系统调用中是较少使用的

  • float:4bytes。
  • double:8bytes。
  • long double:16 bytes。

布尔类

此类仅在C++中定义。几乎没有系统只使用1个bit来表示bool类型,通常使用1个至8个bytes来表示。

标准整数类型

stdint.h或cstdint文件提供了标准化长度的整数数据类型,包括:

  • int8_t, uint8_t
  • int16_t, uint16_t
  • int32_t, uint32_t
  • int64_t, uint64_t
    这些类型依操作系统、处理器、编译器而异调用其他的基本数据类型,可以用书中的例子来查看这些数据类型背后的底层数据类型。
#include <typeinfo>
#include <iostream>
#include <string>
#include <cxxabi.h>

using namespace std;

template <typename T>
string type_name()
{
    int status;
    string name = typeid(T).name();

    auto demangled_name = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status);
    if (status == 0)
    {
        name = demangled_name;
        free(demangled_name);
    }
    return name;
}

template <typename T1, typename T2>
void are_equal()
{
    #define red "\033[1;31m"
    #define reset "\033[0m"
    cout << type_name<T1>() << " vs " << type_name<T2>() << endl;

    if (sizeof(T1) == sizeof(T2))
    {
        cout << " -size:both == " << sizeof(T1) << endl;
    }
    else
    {
        cout << red " -size:"
            << sizeof(T1) << " != " << sizeof(T2)
            << reset << endl;
    }

    if (type_name<T1>() == type_name<T2>())
    {
        cout << " -name:both == " << type_name<T1>() << endl;
    }
    else
    {
        cout << red " -name:"
            << type_name<T1>() << " != " << type_name<T2>()
            << reset << endl;
    }
    
}

int main()
{
    are_equal<uint8_t, int8_t>();
    are_equal<uint8_t, uint32_t>();
    are_equal<signed char, int8_t>();
    are_equal<unsigned char, uint8_t>();
    are_equal<signed short int, int16_t>();
    are_equal<unsigned short int, uint16_t>();
    are_equal<signed int, int32_t>();
    are_equal<unsigned int, uint32_t>();
    are_equal<signed long int, int64_t>();
    are_equal<unsigned long int, uint64_t>();
    are_equal<signed long long int, int64_t>();
    are_equal<unsigned long long int, uint64_t>();
    
    return 0;
}

当需要使用确定长度的整数时,应使用标准整数类型库,让工具帮你转换成对应的底层数据类型。

Structure packing

标准整数类型并不能保证数据占用的空间就是指定的字节数。编译器出于对齐数据或优化性能考虑,可能会用更长的数据类型替换较短的。

#include <iostream>

struct mystruct
{
    uint64_t data1;
    uint16_t data2;
};

int main()
{
    std::cout << "size: " << sizeof(mystruct) << std::endl;
    // size: 16
}

另一个例子:

#include <iostream>

struct mystruct
{
    uint16_t data1:2, data2:14;
    uint64_t data3;
};

int main()
{
    std::cout << "size: " << sizeof(mystruct) << std::endl;
    // size: 16
}

这个结果可能会使你用这个数据结构来访问你的硬件时产生错误,因为两组数据中间填充了6个bytes。解决的办法是

#include <iostream>
#pragma pack(push, 1)
struct mystruct
{
    uint16_t data1:2, data2:14;
    uint64_t data3;
};
#pragma pack(pop)

int main()
{
    std::cout << "size: " << sizeof(mystruct) << std::endl;
    // size: 10
}

上面的#pragma可以使有效数据在内存中保持连续。但是structure packing并不能确保在所有情况下都能实现。比如:

#include <iostream>
#pragma pack(push, 1)
struct alignas(16) mystruct
{
    uint16_t data1;
    uint64_t data2;
};
#pragma pack(pop)

int main()
{
    mystruct s;
    std::cout << "size: " << sizeof(mystruct) << std::endl;
    // size: 16
    std::cout << "address data1: " << &s.data1 << std::endl;
    // 0x7fff09c5e0b0
    std::cout << "address data2: " << &s.data2 << std::endl;
    // 0x7fff09c5e0b2

    return 0;
}

这里要求将结构体在内存中按16字节对齐摆放, 结果就会导致packing后原本占用10bytes的结构体又被扩展为16bytes。

指针类型的大小随CPU、操作系统和程序运行的模式不同而不同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值