offsetof宏的使用、模拟实现及 (size_t)&(((struct_type*)0)->mem_name)的解释

简介: offsetof宏的使用、模拟实现及 (size_t)&(((struct_type*)0)->mem_name)的解释

宏原型:offsetof(type,member)

作用:返回数据结构或联合体类型中成员的偏移量,以字节为单位

返回值:size_t类型的无符号整数

使用案例:

#include <stdio.h>    
#include <stddef.h>   
struct foo {
  char a;
  char b[10];
  char c;
};
int main()
{
  printf("offsetof(struct foo,a) is %d\n", (int)offsetof(struct foo, a));
  printf("offsetof(struct foo,b) is %d\n", (int)offsetof(struct foo, b));
  printf("offsetof(struct foo,c) is %d\n", (int)offsetof(struct foo, c));
  return 0;
}

模拟实现:

#include <stdio.h>
//写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
struct Stu
{
  int a;
  char c;
  double d;
};
#define OFFSETOF(struct_type, mem_name)      (size_t)&(((struct_type*)0)->mem_name)
//这样的强制类型转换应该使用 (size_t) 而不是 (int) 
//为了确保能够存储较大范围内的偏移值
int main()
{
  printf("%d\n", OFFSETOF(struct Stu, a));
  printf("%d\n", OFFSETOF(struct Stu, c));
  printf("%d\n", OFFSETOF(struct Stu, d));
  return 0;
}

关于“(size_t)&(((struct_type*)0)->mem_name)”的解释:

       该表达式的作用是用于获取结构体成员相对于结构体在内存中的偏移量,它将 0 强制类型转换为指向 struct_type 类型的空指针,获取结构体中成员的地址后再强制转换为无符号整型size_t。

注意事项:

  1. 这种技巧通常用于底层编程或者涉及到直接操作内存布局和字节对齐等细节时。一般情况下,在正常应用程序开发过程中不建议频繁使用此类技巧。
  2. 在实际应用时,请确保遵循相关语言和平台规范,并小心处理可能出现未定义行为或错误结果的情况。

关于“(struct_type*)0”的解释:

       在 C 和 C++ 中,整数 0 可以被隐式地转换为空指针。

注意事项:在实际应用中,并不推荐将整数 0 直接强制转换为空指针。根据 C 和 C++ 的规范,在大多数情况下,应该使用 NULL 或 nullptr 来表示空指针。

关于将地址强制类型转换为size_t类型后如何获取偏移量的解释:

#include <stdio.h>
typedef struct {
    int member1;
    char member2;
    double member3;
} MyStruct;
int main() {
    MyStruct myStruct;
    // 获取成员变量的地址
    int* ptr_member1 = &myStruct.member1;
    char* ptr_member2 = &myStruct.member2;
    size_t member1 = ptr_member1;
    size_t member2 = ptr_member2;
    size_t all = &myStruct;
    printf("%u\n", all);
    printf("%u\n", member1);
    printf("%u\n", member2);
    return 0;
}

       在这里我们获取了结构体本身地址强制类型转换为size_t后的值2845767320,以及它的两个成员强转后的值2845767320和2845767324,我们可以发现貌似只需要对这些值进行简单的减法运算就可以得到结构体每个成员相对于结构体在内存上的偏移量,但是我们发现关于#OFFSETOF自定义宏包括主函数中并未提及减法操作,但还是得到了相应的偏移量,这是因为:编译器在处理空指针时会有隐式行为:在获取结构体成员地址时,默认情况下编译器会计算出从起始位置(即空指针)到该成员之间的偏移量。然后就该偏移量被强制类型转换为size_t型输出......

~over~

相关文章
|
9月前
|
编译器 C++
struct 和 typedef struct 区别和用法总结
struct 和 typedef struct 区别和用法总结
174 0
|
9月前
|
C语言
typedef 和 # define 用法区别
typedef 和 # define 用法区别
80 0
|
C++ 编译器
Effective C++ 笔记(2):尽量以const,enum,inline替换#define
条款二(clause 2) 尽量使用const,enum,inline替换#define(以编译器替换预处理器) 1、使用const替换#define 通常替换 #define NUM 3.
1126 0
|
存储 C语言 C++
C++ sizeof用法 .
sizeof   sizeof操作符的作用是返回一个对象或类型名的长度,长度的单位是字节。 返回值的类型是标准库命名为size_t的类型,size_t类型定义在cstddef头文件中,该头文件是C标准库的头文件stddef.h的C++版本。
1117 0
#define和typedef的简单区别及使用
/* ============================================================================ Name : TestDefine.
926 0
|
C语言
#define和typedef的区别
typedef和#define都是替一个对象取一个别名,来增强程序的可读性,但是它们有以下几个区别 1. 原理不同    (1)#define是C语言中定义的语法,它是预处理指令,在预处理的时候进行简单的字符串替换,不作任何的正确性的检查,不管是否正确照样带入替换,只有在编译的时候才会发现错误并报错    (2)typedef是关键字,在编译的时候处理,所以typedef是有类型检查的功能,在作用域内给类型定一个别名 2. 功能不同。
1115 0
#define与typedef区别
1) #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。例如: #define PI 3.1415926 程序中的:area=PI*r*r 会替换为3.1415926*r*r 如果你把#define语句中的数字9 写成字母g 预处理也照样带入。
992 0
|
C语言 C++ 编译器
C/C++语法知识:typedef struct 用法详解
第一篇:typedef struct与struct的区别 1. 基本解释 typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。
6451 0

热门文章

最新文章