C基本知识
C基本数据类型
C基本的数据类型说明:
| C declaration | Bytes | ||
|---|---|---|---|
| Signed | Unsigned | 32-bits | 64-bits |
| [signed]char | unsigned char | 1 | 1 |
| short | unsigned short | 2 | 2 |
| int | unsigned | 4 | 4 |
| long | unsigned long | 4 | 8 |
| int32_t | uint32_t | 4 | 4 |
| int64_t | uint64_t | 8 | 8 |
| char * | 4 | 4 | |
| float | 4 | 4 | |
| double | 8 | 8 |
字节序
测试代码:
#include <stdio.h>
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, int len)
{
int i;
for (i = 0; i < len; i++) {
printf(" %.2x", start[i]);
}
printf("\n");
}
int main(void)
{
int x = 0x01234567;
show_bytes((byte_pointer)&x, sizeof(x));
return 0;
}
编译运行测试:
$ gcc endian.c
$ ./a.out
67 45 23 01
可以看出,当前我运行的机器是小端序。
结构体
参考:C语言技术天花板【结构体】一节课掌握_哔哩哔哩_bilibili
结构体中成员排列的规则:
-
结构体成员的内部偏移量(内部地址),要被这个成员的数据类型的大小整除。
struct test { int a; /* [Byte][Byte][Byte][Byte] */ char c; /* [Byte][0x00] */ short s; /* [Byte][Byte] */ };/* 结构体的内存大小 */ sizeof(struct test) = 8; /* 结构体中的内存分布,可看出成员c后面填充了1Byte的0x00 */ struct test test1 = {0}; test1.a = 0x12345678; test1.c = 0xbb; test1.s = 0xccdd; (gdb) x /8bx &test1 0x7fffffffe110: 0x78 0x56 0x34 0x12 0xbb 0x00 0xdd 0xcc -
整个结构体的大小,必须是最大成员的size的整数倍,否则就需要在末尾填充空白字节。
struct test { int a; /* [Byte][Byte][Byte][Byte] */ char c; /* [Byte] */ };/* 结构体的内存大小 */ sizeof(struct test) = 8; /* 结构体中的内存分布,可看出成员c后面填充了3Byte的0x00 */ (gdb) x /8bx &test1 0x7fffffffe110: 0x78 0x56 0x34 0x12 0xbb 0x00 0x00 0x00 -
对于结构体中的结构体,按照结构体展开之后的内存对齐来处理。
struct test1 { int a; /* [Byte][Byte][Byte][Byte] */ short s; /* [Byte][Byte][0x00][0x00] */ }; struct test { int a; /* [Byte][Byte][Byte][Byte] */ char c; /* [Byte][0x00][0x00][0x00]*/ struct test1 s; };/* 结构体的内存大小为16,根据规则1,成员c后面补充3Bytes的0x0,根据规则2,s.s成员后面补充2Bytes的0x0 */ sizeof(struct test) = 16; /* 结构体中的内存分布 */ struct test test1 = {0}; test1.a = 0x12345678; test1.c = 0xff; test1.s.a = 0xaabbccdd; test1.s.s = 0x9988; (gdb) x /16bx &test1 0x7fffffffe100: 0x78 0x56 0x34 0x12 0xff 0x00 0x00 0x00 0x7fffffffe108: 0xdd 0xcc 0xbb 0xaa 0x88 0x99 0x00 0x00 -
认为指定特殊的对齐规则,使用
#pragma pack(n)指定每个成员的其实地址,按照n来对齐,覆盖第一条规则。如果整个n比第一条规则对齐还要大,那么就取小的。#pragma pack(2) struct test1 { int a; /* [Byte][Byte][Byte][Byte] */ short s; /* [Byte][Byte] */ }; struct test { int a; /* [Byte][Byte][Byte][Byte] */ char c; /* [Byte][0x00] */ struct test1 s; };/* 结构体的内存大小为12,根据规则4,成员c后面补充1Bytes的0x0 */ sizeof(struct test) = 12; /* 结构体中的内存分布 */ struct test test1 = {0}; test1.a = 0x12345678; test1.c = 0xff; test1.s.a = 0xaabbccdd; test1.s.s = 0x9988; (gdb) x /12bx &test1 0x7fffffffe110: 0x78 0x56 0x34 0x12 0xff 0x00 0xdd 0xcc 0x7fffffffe118: 0xbb 0xaa 0x88 0x99#pragma pack(8) struct test1 { int a; /* [Byte][Byte][Byte][Byte] */ short s; /* [Byte][Byte] */ }; struct test { int a; /* [Byte][Byte][Byte][Byte] */ char c; /* [Byte][0x00] */ struct test1 s; }; /* 规则1生效 */ sizeof(struct test) = 16; -
不使用任何对齐,直接存放数据的方式,使用
#pragma pack(1)。#pragma pack(1) struct test1 { int a; /* [Byte][Byte][Byte][Byte] */ short s; /* [Byte][Byte] */ }; struct test { int a; /* [Byte][Byte][Byte][Byte] */ char c; /* [Byte] */ struct test1 s; };/* 结构体的内存大小为11,各个成员之间不会填充0x0 */ sizeof(struct test) = 11; /* 结构体中的内存分布 */ struct test test1 = {0}; test1.a = 0x12345678; test1.c = 0xff; test1.s.a = 0xaabbccdd; test1.s.s = 0x9988; (gdb) x /11bx &test1 0x7fffffffe110: 0x78 0x56 0x34 0x12 0xff 0xdd 0xcc 0xbb 0x7fffffffe118: 0xaa 0x88 0x99
一个有趣的函数offsetof,可以用来计算结构体成员在结构体中的偏移位置,比如:
#include <stdio.h>
#include <stddef.h>
struct foo {
char common[64];
// This is anonymous.
union {
struct {
char x;
int y;
int z;
};
struct {
char u;
char v;
char w[0];
};
};
};
#define display_offset(member) \
printf("foo." #member " is at %d\n", \
offsetof(struct foo, member) \
)
int main() {
display_offset(common);
display_offset(x);
display_offset(y);
display_offset(z);
display_offset(u);
display_offset(v);
display_offset(w);
}
运行结果:
$ ./offsetof
foo.common is at 0
foo.x is at 64
foo.y is at 68
foo.z is at 72
foo.u is at 64
foo.v is at 65
foo.w is at 66

浙公网安备 33010602011771号