【问题标题】:The usage of `sizeof` in CC中`sizeof`的用法
【发布时间】:2016-02-24 08:51:07
【问题描述】:

我在看redis的源码。 代码如下:

typedef char *sds;

struct sdshdr {
    unsigned int len;
    unsigned int free;
    char buf[];
};

static inline size_t sdslen(const sds s) {
    struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
    return sh->len;
}

static inline size_t sdsavail(const sds s) {
    struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
    return sh->free;
}

关于这段代码,我有一些问题:

  1. 为什么sizeof(struct sdshdr)的输出是8?为什么不包括char buf[]
  2. 我无法理解函数size_t sdslensdsavail。为什么struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));

【问题讨论】:

  • 演员阵容毫无意义。您不能安全地将字符指针转换为结构指针,它违反了严格的别名。此外,将指针隐藏在 typedef 后面是非常糟糕的做法。
  • @Lundin 这就是(void *) 演员修复的内容,对吧?传入指针是char *s,您可以从中减去。然后将结果转换为void *,它可以很好地转换为struct shshdr *(但更短更通用)。
  • @Lundin 我很确定这里没有字符串别名问题,因为指针的值已经改变并且在减法之后指向实际的结构对象。例如,如果字符串本身将被重新解释为结构,但事实并非如此。 Struct 被解释为使用兼容类型的结构。 (char* 也可以指向任何对象。)

标签: c redis


【解决方案1】:

  • char buf[] 没有分配任何内存,因此它不占用空间,因此充当灵活数组,因此 2 int 数据类型最终占用 4+4 = 8 个字节。

  • size_t 中,传递的变量是属于*sdss,它是char 的typedef

    这导致这段代码在内存中的实现。

    if (init) {
        sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
      } else {
        sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
      }
      if (sh == NULL) return NULL;
      sh->len = initlen;
      sh->free = 0;
      if (initlen && init)
        memcpy(sh->buf, init, initlen);
      sh->buf[initlen] = '\0';
      return (char*)sh->buf;
    }
    

    它存储的内存空间等于 sh sdshdr 结构。

  • 【讨论】:

    • 你能给我详细解释一下struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));吗?我看不懂。
    • s 是内存中的一个指针,它似乎指向struct sdshdr 之后,然后s-(sizeof(...) 计算这个就在结构之前的地址。可以写成((struct sdshdr *)s)-1
    • @BlackMamba:这一行的作用是为 sh = malloc/calloc 创建一个内存空间,然后检查该字符是否为 的初始长度并在末尾添加 1。然后它设置它的完整长度并检查该行的内存是否可用于初始化,在初始化之后它会为 *s 的结尾附加一个 '\0',然后它将缓冲区返回给程序,该缓冲区必须是一种 'sds ' 是 char 因此 return 语句以 return char* sh->buf 结束。希望这很清楚,如果您的问题得到解决,请点赞:)
    • @DanyalImran 我找到了这个链接,我现在很清楚了:redis.io/topics/internals-sds
    • @BlackMamba 太好了:D
    【解决方案2】:
    1. 0 大小的数组没有大小,它的声明长度为 0。这是一个灵活的数组成员;它只能出现在struct 的末尾。
    2. 初始化设置sh 指向通过取s 的值计算的内存,char *,减去 sds 标头的大小。换句话说,我们从指向字符串第一个字符(灵活数组成员)的指针计算出指向标头本身的指针,这样我们就可以得到长度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-26
      • 2010-09-10
      • 1970-01-01
      • 1970-01-01
      • 2011-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多