C++字节存储方式和reinterpret_cast

数据存储方式和数据类型

变量

变量可以认为是一个内存块,该内存块中存放了变量的二进制表示格式。其实,汇编语言中,没有变量类型的概念,而在C等静态高级语言中,都有变量类型的概念。

1字节 = 1B = 8bit = 2^8 => 0-256
所以ASCII标准字符有256个,sizeof(int) = 4,因此int最大是 2 ( 8 × 4 − 1 ) 2^{(8 \times 4 - 1)} 2(8×41)-1是因为有符号位

可以这么理解,变量类型只是程序员告诉编译器变量的表示方式;而最终的汇编形式,仍然是没有数据类型的。我们的一些操作,需要变量类型,因为编译器需要根据变量的类型,完成与该类型有关的操作,比如int赋值、加减乘除和比较大小等,都是4个字节的操作等。

可以这么理解,变量类型相当于一个操作协议,凡是同一种类型,都可以进行该类型协议的操作,保证操作的正确性。程序定义好类型之后,就可以按照类型,来执行符合类型的操作。

比如有结构体:

struct S {
    int a;
    char b;
};

该结构体的sizeof(S)是8,因为int有4个字节,char有1个字节,但是编译器会有align操作,以满足快速读取的需求,4 + 1 = 5,最接近8=2^3,因此是8字节。

因此,只要有一个足够内存,我们就可以直接序列化该结构体,然后写入即可。一般来说,连续的内存用char*来表示。见下文序列化实例。

指针

指针用来表示一段地址,64位系统中,指针都是8字节长度,可以指向任意地方。同样的,指针的类型,意义仅仅是为了在语言级别限制操作等。指针可以类型转换,转换之后就可以指向不同的地址了。不过,这么做代表了操作的转变,还是谨慎些。void*可以被任何指针指向。

函数

函数指针,仅仅表示一个代码段的执行起始地址。

测试代码实例

以下代码说明了数据格式转化的本质,注意字符串的内存布局。假设有字符串"abc",则内存的表示是:

a  97      b 98      c 99
01100001 | 01100010 | 01100011

而每个字符是从右往左计算,注意0补位

#include <cstdio>
#include <cstdlib>
#include <strings.h>

template<typename T>
size_t serialize(const T& obj, char* buf, size_t len) {
    if (len < sizeof(obj)) {
        return -1;
    }
    *reinterpret_cast<T*>(buf) = obj;
    return sizeof(obj);
}

template<typename T>
size_t deserialize(T& obj, char* buf, size_t len) {
    if (len < sizeof(obj)) {
        return -1;
    }
    obj = *reinterpret_cast<T*>(buf);
    return sizeof(obj);
}

struct S {
    int a;
    char b;
    char str[100];
    int arr[10];
};

void printS(const S& s) {
    printf("%d\n", s.a);
    printf("%d\n", s.b);
    printf("%s\n", s.str);
    for (int i = 0; i < sizeof(s.arr) / sizeof(int); i++) {
        printf("%d ", s.arr[i]);
    }
    printf("\n");
}

int main() {
    printf("basic test =================\n");
    S s1;
    bzero(&s1, sizeof(s1));
    s1.a = 10;
    s1.b = 's';
    sprintf(s1.str, "hello world! This is a data type test");
    for (int i = 0; i < 10; ++i) {
        s1.arr[i] = i;
    }
    int N = 256;
    char buf[N];
    size_t ret = serialize(s1, buf, N);
    printf("serialize ret = %d\n", ret);
    S s2;
    ret = deserialize(s2, buf, N);
    printf("deserialize ret = ", ret);
    printS(s2);

    printf("\npointer test =================\n");
    int* a = (int*)malloc(sizeof(int));
    *a = 100;
    char* b = (char*)a;
    printf("%d %d\n", *a, *b);
    printf("%c\n", *a);

    bzero(buf, N);
    sprintf(buf, "aaaa");
    typedef long long LL;
    int* num;
    num = (int*)buf;
    printf("%d\n", *num);
    return 0;
}

最终输出:

basic test =================
serialize ret = 148
deserialize ret = 10
115
hello world! This is a data type test
0 1 2 3 4 5 6 7 8 9

pointer test =================
100 100
d
1633771873
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值