PHP

【笔记】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.png

gcc 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.png

gcc 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

上一篇 下一篇

猜你喜欢

热点阅读