数据存储方式和数据类型
变量
变量可以认为是一个内存块,该内存块中存放了变量的二进制表示格式。其实,汇编语言中,没有变量类型的概念,而在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×4−1),-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