【笔记】PHP7的基本变量:struct、union、大小端
2019-04-17 本文已影响15人
言十年
php版本php-7.1.17
鸣谢课程 《PHP7的基本变量》https://www.imooc.com/learn/1085
struct 与 union
struct
#include<stdio.h>
struct _s {
char a; // 1字节
int b; // 4字节
long c; // 8字节
void* d; // 8字节
int e; // 4字节
char* f; // 8字节
} s;
int main() {
s.a = 'a';
s.b = 1;
s.c = 2;
s.d = NULL;
s.e = 3;
s.f = &s.a;
printf("struct size %lu \n", sizeof(s));
return 0;
}
其实这个结构体并不是33个字节。而是40字节。
这就说到struct的对齐问题了。
它们整体按照8字节对齐。
image.pnggcc struct.c -g -o struct ,加上 -g 是为使用gdb可以很方便的查看里面的变量。
打印变量值。
(gdb) b main
Breakpoint 1 at 0x4004c8: file struct.c, line 13.
(gdb) r
Starting program: /root/c/struct
Breakpoint 1, main () at struct.c:13
13 s.a = 'a';
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.209.el6_9.2.x86_64
(gdb) p s
$1 = {a = 0 '\000', b = 0, c = 0, d = 0x0, e = 0,
f = 0x0}
(gdb) n
14 s.b = 1;
(gdb) p s
$2 = {a = 97 'a', b = 0, c = 0, d = 0x0, e = 0,
f = 0x0}
验证内存对齐。
$3 = 0x600900 "a"
(gdb) p &s.b
$4 = (int *) 0x600904
(gdb) p &s.c
$5 = (long int *) 0x600908
(gdb) p &s.d
$6 = (void **) 0x600910
(gdb) p &s.e
$7 = (int *) 0x600918
(gdb) p &s.f
$8 = (char **) 0x600920
看打印的内存地址。
union
#include<stdio.h>
union _u {
char a;
int b;
long c;
void* d;
int e;
char* f;
} u;
int main() {
u.a = 'a';
u.b = 1;
u.c = 2;
u.d = NULL;
u.e = 3;
u.f = &u.a;
printf(" union size %lu\n", sizeof(u));
return 1;
}
union 会用同一块内存。上面的u大小为8字节。
image.pnggcc union.c -g -o union
(gdb) n
14 u.b = 1;
(gdb) p u
$2 = {a = 97 'a', b = 97, c = 97, d = 0x61, e = 97,
f = 0x61 <Address 0x61 out of bounds>}
(gdb) p &u.a
$3 = 0x6008e0 "a"
(gdb) p &u.b
$4 = (int *) 0x6008e0
(gdb) p &u.c
$5 = (long int *) 0x6008e0
宏和大小端的概念
_zval_struct
struct _zval_struct {
zend_value value; /* value */
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type, /* active type */
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved) /* call info for EX(This) */
} v;
uint32_t type_info;
} u1;
union {
uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* literal cache slot */
uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */
uint32_t fe_pos; /* foreach position */
uint32_t fe_iter_idx; /* foreach iterator index */
uint32_t access_flags; /* class constant access flags */
uint32_t property_guard; /* single property guard */
uint32_t extra; /* not further specified */
} u2;
};
#ifdef WORDS_BIGENDIAN
……
# define ZEND_ENDIAN_LOHI_4(a, b, c, d) d; c; b; a;
……
#else
……
# define ZEND_ENDIAN_LOHI_4(a, b, c, d) a; b; c; d;
……
#endif
0x12345678
大端:低位放到高地址,高位放到低地址。0x12 34 56 78
小端:低位放到低地址,高位放到高地址。0x78 56 34 12
验证大小端
#include<stdio.h>
void func1() {
int i = 0x12345678;
if (*((char*)&i) == 0x12) {
printf("func1 says Big endian!\n");
} else {
printf("func1 says Little endian!\n");
}
return ;
}
void func2() {
union _u {
int i;
char c;
}u;
u.i = 1;
if (u.c == 1) {
printf("func2 says Little endian!\n");
} else {
printf("func2 says Big endian!\n");
}
return ;
}
int main() {
func1();
func2();
return 1;
}
gcc bigorlittleendian.c -g -o bigorlittleendian
(gdb) b func1
Breakpoint 1 at 0x4004cc: file bigorlittleendian.c, line 4.
(gdb) r
Starting program: /root/c/bigorlittleendian
Breakpoint 1, func1 () at bigorlittleendian.c:4
4 int i = 0x12345678;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.209.el6_9.2.x86_64
(gdb) n
5 if (*((char*)&i) == 0x12) {
(gdb) p/x i #p/x i 表示按照十六进制格式显示变量
$1 = 0x12345678
(gdb) x/b &i # x是examine ,b表示单字节,x/b查看单字节内存
0x7fffffffe44c: 0x78
(gdb) x/4 &i
0x7fffffffe44c: 0x78 0x56 0x34 0x12
(gdb) x/16 &i # 可以看出 内存地址从低向高增长。
0x7fffffffe44c: 0x78 0x56 0x34 0x12 0x60 0xe4 0xff 0xff
0x7fffffffe454: 0xff 0x7f 0x00 0x00 0x35 0x05 0x40 0x00
参考资料:
*《C语言的struct的数据成员对齐》https://www.cnblogs.com/fengfenggirl/p/struct_align.html
*《 轻松记住大端小端的含义(附对大端和小端的解释)》http://www.cnblogs.com/wuyuegb2312/archive/2013/06/08/3126510.html