redis 之 sds (二) char []

可以先看看:

https://my.oschina.net/tsh/blog/974033

http://coolshell.cn/articles/11377.html 

这两篇文章。

下面同样通过一个列子来说明:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>

struct __attribute__((__packed__)) A 
{
    int32_t num;
    char flags;
    char str[];
};

int main(int argc, char *argv[])
{
    printf("struct A size = %u\n", sizeof(struct A));
    printf("struct A [num  addr = %d]\n", &(((struct A *)NULL)->num));
    printf("struct A [flags addr = %d]\n", &(((struct A *)NULL)->flags));
    printf("struct A [str   addr = %d]\n", &(((struct A *)NULL)->str));

    return 0;
}

编译输出:

struct A size = 5
struct A [num  addr = 0]
struct A [flags addr = 4]
struct A [str   addr = 5]

通过使用了 __attribute__((__packed__)) 得到了  

struct A 的大小为 5    (int32_t) + (char) = 4 + 1 = 5  发现  char str[] 并没有占用结构体的大小。

接着往下看代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>

struct __attribute__((__packed__)) A 
{
    char flags;
    char str[];
};

int main(int argc, char *argv[])
{
    struct A *a1 = (struct A *)malloc(sizeof(struct A) + 100);
    
    printf("addr: a1 = %p, a1->flags = %p, a1->str = %p\n", 
            a1, &(a1->flags), a1->str);
    
    a1->flags = 'A';
    a1->str[0] = 'Z';
    a1->str[1] = 'Y';
    a1->str[2] = 'X';
    a1->str[3] = '\0';
    
    printf("%s\n", (char *)a1);

    char *str = a1->str;

    printf("str = %s\n", str);
    printf("str[-1] = %c \n", str[-1]);
    printf("str[-1] = %p\n", &str[-1]);

    free(a1);
    a1 = NULL;

    return 0;
}

输出:

addr: a1 = 0x143d010, a1->flags = 0x143d010, a1->str = 0x143d011
AZYX
str = ZYX
str[-1] = A 
str[-1] = 0x143d010

这里申请了 101 字节的存储空间

150614_7qU8_98920.png

从图中可以看到  str[-1]  = flag  ,  如果已知了 str 那么我们只要 通过  str - sizeof(struct A) 就可以知道 这个结构体的起始地址.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>

struct __attribute__((__packed__)) A 
{
    char flags;
    char str[];
};

int main(int argc, char *argv[])
{
    struct A *a1 = (struct A *)malloc(sizeof(struct A) + 100);
    
    printf("addr: a1 = %p, a1->flags = %p, a1->str = %p\n", 
            a1, &(a1->flags), a1->str);
    
    char *str = a1->str;

    printf("str[-1] = %p\n", &str[-1]);
    
    struct A *a2 = (struct A *)((str) - sizeof(struct A));
    struct A *a3 = (struct A *)((str) - ((size_t)&((struct A *)NULL)->str)); 

    printf("a1 = %p\n", a1);
    printf("a2 = %p\n", a2);
    printf("a3 = %p\n", a3);
    printf("struct A size = %u, str = %u\n", sizeof(struct A), &((struct A *)NULL)->str);

    free(a1);
    a1 = NULL;
    a2 = a3 = NULL;

    return 0;
}

编译输出:

addr: a1 = 0x1d21010, a1->flags = 0x1d21010, a1->str = 0x1d21011
str[-1] = 0x1d21010
a1 = 0x1d21010
a2 = 0x1d21010
a3 = 0x1d21010
struct A size = 1, str = 1

在 redis 中大部分的  sds 都会用到  通过   str[-1] 这种方式去获得 flags, 以及 通过  sds - 结构体大小 获得结构体的起始地址操作.

其是在 linux 中 有个宏也可以得到结构体对应成员变量的偏移。

文件: stddef.h  offsetof

#ifndef _LINUX_STDDEF_H
#define _LINUX_STDDEF_H

#include <linux/compiler.h>

#undef NULL
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif

#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

#endif

 

还是用代码说话 (来自  man -a offsetof):

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    struct s {
        int i;
        char c;
        double d;
        char a[];
    };

    /* Output is compiler dependent */

    printf("offsets: i=%ld; c=%ld; d=%ld a=%ld\n",
            (long) offsetof(struct s, i),
            (long) offsetof(struct s, c),
            (long) offsetof(struct s, d),
            (long) offsetof(struct s, a));
    printf("sizeof(struct s)=%ld\n", (long) sizeof(struct s));

    exit(EXIT_SUCCESS);
}

编译输出:

offsets: i=0; c=4; d=8 a=16
sizeof(struct s)=16

 

转载于:https://my.oschina.net/tsh/blog/1491301

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值