我们对C语言中的struct的印象是什么?
- 它是C语言中内置的复合数据类型;
- 相当于C++中的class;
- 丰富的初始化操作;
- Struct的拷贝为浅拷贝;
- 支持嵌套、指针等操作;
- 支持位字段,节省空间。
如果你知道的只有这些,那么说明你对struct了解的还不够深刻,后续我们简单聊聊结构体的一些知识。
1. C++中的struct本文的代码以及描述都是基于linux环境。
C++中的struct本质上和class没有区别,struct也支持构造函数、成员函数、虚函数、继承等,仅仅只有默认的访问权限和成员初始化和class不太一样。看一下下面的结构体相关的代码:
struct STest {
public:
int a:8;
int b:8;
int c:8;
int d:8;
STest() {reset();}
bool is_valid() const;
void reset();
};
从上面的例子中,可以看到struct和clall几乎没有什么区别,那么我们到底该如何使用class、struct呢?推荐的用法是这样的:
- struct仅被用在包含公有数据的消极变量上,可以包含有关联的常量,以及reset、is_valid、序列化、反序列化这样的通用函数;
- 其他情况都应该用class。
struct的对齐原则是:
- 结构体变量中成员的偏移量必须是成员大小的整数倍;
- 结构体总大小必须是所有成员大小的公倍数;
- 结构体的总大小为结构体对齐字节数大小的整数倍。
举个例子,看一下下面的代码:
// file: align.c // gcc align.c -o align #include#include struct Test1 { int64_t a; int8_t b; int32_t c; int8_t d; }; struct Test2 { int64_t a; int8_t b __attribute__((aligned(16))); int32_t c; int8_t d; }; struct Test3 { int64_t a; int8_t b ; int32_t c; int8_t d; } __attribute__((aligned(16))); int main() { struct Test1 t1; struct Test2 t2; struct Test3 t3; printf("sizeof(t1) = %dn", sizeof(t1)); printf("sizeof(t2) = %dn", sizeof(t2)); printf("sizeof(t3) = %dn", sizeof(t3)); printf("t1 &a = 0x%p, &b = 0x%p, &c= 0x%p &d = 0x%pn", &t1.a, &t1.b, &t1.c, &t1.d); printf("t2 &a = 0x%p, &b = 0x%p, &c= 0x%p &d = 0x%pn", &t2.a, &t2.b, &t2.c, &t2.d); printf("t3 &a = 0x%p, &b = 0x%p, &c= 0x%p &d = 0x%pn", &t3.a, &t3.b, &t3.c, &t3.d); }
输出结果:
$ ./align sizeof(t1) = 24 sizeof(t2) = 32 sizeof(t3) = 32 t1 &a = 0x0x7ffcfaeb0830, &b = 0x0x7ffcfaeb0838, &c= 0x0x7ffcfaeb083c &d = 0x0x7ffcfaeb0840 t2 &a = 0x0x7ffcfaeb0810, &b = 0x0x7ffcfaeb0820, &c= 0x0x7ffcfaeb0824 &d = 0x0x7ffcfaeb0828 t3 &a = 0x0x7ffcfaeb07f0, &b = 0x0x7ffcfaeb07f8, &c= 0x0x7ffcfaeb07fc &d = 0x0x7ffcfaeb0800
可以通过下面的图片简单看下这个结构体在不同对齐情况下的内存分布:
我们来设计这样一个数据页,如下图:
实现的方式有很多,最简单高效的应该就是用struct了,代码如下:
// file: page.c // g++ page.c -o page #include#include #include #include typedef struct __attribute__((packed)) { static const uint32_t PAGE_SIZE = 16384; static const uint8_t CRC_SIZE = 4; uint32_t magic; uint32_t version; uint32_t header_size; uint32_t payload_size; uint32_t padding_size; char data[0]; } simple_page_t; int serialize_data(char *data) { int data_size = 10240; memset(data, 'd', data_size); return data_size; } void padding_data(char *data, uint32_t padding_size) { memset(data, 'p', padding_size); } void set_checksum(int32_t *data) { *data = 123; // todo } int main() { simple_page_t *page = (simple_page_t *)malloc(simple_page_t::PAGE_SIZE); page->magic = 1001; page->version = 1; page->header_size = sizeof(*page); page->payload_size = serialize_data(page->data); page->padding_size = simple_page_t::PAGE_SIZE - page->header_size - page->payload_size - simple_page_t::CRC_SIZE; padding_data(page->data + page->header_size + page->payload_size, page->padding_size); set_checksum((int32_t*)page->data + simple_page_t::PAGE_SIZE - simple_page_t::CRC_SIZE); // write page (16KB) to file. printf("header-size = %dn", page->header_size); }
就是这么简单,加上相关的测试代码总共才40行左右。
写在后面本文就写到这里,你还了解哪些struct实用开发技巧呢,欢迎留言。



