c_cpp 使用地址偏移量包含N个元素的数组成员计算struct的大小

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 使用地址偏移量包含N个元素的数组成员计算struct的大小相关的知识,希望对你有一定的参考价值。

#include <assert.h> // for assert
#include <stdio.h>  // for printf
#include <stdlib.h> // for malloc

#define fieldOffset(type, field) ((size_t) &((type *) 0)->field)
#define ContainerPointer(ptr, type, member) ({ \
  const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  (type *)( (char *)__mptr - fieldOffset(type,member) );})


// No Memory Alignment with GCC
struct Foo {
  int a;        // 4 bytes
  double b[1];  // 8 bytes
} __attribute__((packed));;
typedef struct Foo Foo;

// Memory Alignment with GCC(Non-packed)
// struct Foo {
//   int a;        // 4 bytes
//   double b[1];  // 8 bytes
// }

int main()
{
  printf("size of Foo: %lu\n", sizeof(Foo));

  //  Foo
  // +------+ <--- 0
  // | a    |
  // +------+
  // | b    |
  // |      |
  // +------+
  Foo* f = 0;
  printf("address of f: %p\n", f);
  printf("address of f->a: %p\n", &f->a);

  //  Foo
  // +------+ <--- 0  ^
  // | a    |         | 4
  // +------+ <--- 4  v
  // | b[0] |
  // |      |
  // +------+
  // so &f->b[0] - f = &f->b[0] = 4 = sizeof(a)
  printf("address of f->b: %p\n", &f->b);
  printf("address of f->b[0]: %p\n", &f->b[0]);

  //  Foo
  // +------+ <--- 0
  // | a    |
  // +------+ <--- 4  ^
  // | b[0] |         | 8
  // |      |         |
  // +------+ <--- 12 v
  // | b[1] |
  // |      |
  // +------+
  // so &f->b[1] - f = &f->b[1] = 12 = sizeof(a) + 1 * sizeof(b)
  printf("address of f->b[1]: %p\n", &f->b[1]);

  //  Foo
  // +------+ <--- 0
  // | a    |
  // +------+ <--- 4
  // | b[0] |
  // |      |
  // +------+ <--- 12 ^
  // | b[1] |         | 8
  // |      |         |
  // +------+ <--- 20 v
  // | b[2] |
  // |      |
  // +------+
  // so &f->b[2] - f = &f->b[2] = 20 = sizeof(a) + 2 * sizeof(b)
  printf("address of f->b[2]: %p\n", &f->b[2]);

  // In the same way, the sizeof(a) + N * sizeof(b) = &f->b[N], so we can use
  // fieldOffset(Foo, b[N]) to allocate an struct Foo with N double elements.
  // fieldOffset interprets address 0 as a pointer for struct Foo and use
  // the above offset trick to calculate the size of Foo's field,
  // 'a' and N numbers of 'b'.
  unsigned int N = 5, size = 0;
  size = sizeof(Foo) + sizeof(double) * (N-1);
  assert(N >=0 && fieldOffset(Foo, b[N]) == size);

  printf("Allocate struct Foo with %d double members:\n", N);
  Foo* p = (Foo*) calloc(1, fieldOffset(Foo, b[N]));
  p->a = N;
  unsigned int i = 0;
  for (i = 0 ; i < N ; ++i) {
    p->b[i] = (double)i;
    printf("p->b[%d] = %lf\n", i, p->b[i]);
  }
  // p->b[N] = 1.0; // Overflow!

  for (i = 0 ; i < N ; ++i) {
    f = ContainerPointer(&p->b[i], Foo, b[i]);
    printf("container of %p is %p\n", &p->b[i], f);
    assert(f == p);
  }

  return 0;
}

以上是关于c_cpp 使用地址偏移量包含N个元素的数组成员计算struct的大小的主要内容,如果未能解决你的问题,请参考以下文章

计算结构体内元素的偏移量宏

C语言进阶自定义类型

什么是二维数组偏移量?

获取C++类成员变量的地址偏移

CUDA 通过数组偏移量从设备内存中复制单个元素是不是安全?

指针和数组的关系