offset宏定义_vba offset 用法

offset宏定义_vba offset 用法C语言面试的时候可能会考,这样的宏定义:#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)函数作用:计算结构体成员的偏移,有些自有代码里也会手写这样的代码,实际上这个函数是标准实现的。实际上如果我们浏览ANSIC编译器的标头文件,将在stddef.h中遇到这样奇怪的宏。这个红具有可怕的声明。此…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

C语言面试的时候可能会考,这样的宏定义:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)

函数作用:计算结构体成员的偏移,有些自有代码里也会手写这样的代码,实际上这个函数是标准实现的。实际上如果我们浏览 ANSI C 编译器的标头文件,将在 stddef.h 中遇到这样奇怪的宏。这个红具有可怕的声明。此外,如果您查阅编译器手册,您会发现一个无益的解释,上面写着如下:

offsetof() 宏返回结构或联合复合中元素名称的偏移量。这提供了一种可移植的方法来确定偏移量。

函数的声明是这样的

size_t offsetof(type, member);

函数描述:

offset宏 从结构类型的开头返回字段成员的偏移量。

此宏很有用,因为组成结构的字段的大小可能因实现而异,并且编译器可能在字段之间插入不同数量的填充字节。因此,元素的偏移量不一定由前一个元素的大小之和给出。

如果成员不与字节边界对齐(例如,它是位字段),则会产生编译器错误。

返回值:

返回给定类型中给定成员的偏移量(以字节为单位)

标准:C89, C99, POSIX.1-2001

源代码:


#include <iostream>
using namespace std;

int main()
{
	struct Demo{
		int a;
		char b;
		double c;
		char d[];
	};

	/* Output is compiler dependent */

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

	exit(EXIT_SUCCESS);

}

输出结果:

sizeof(struct Demo)=16
offsets: a=0; b=4; c=8 d=16

我们先来搞明白这个工作原理再看他到底有啥妙用。

offset的工作原理:

offset宏的偏移量是 ANSI 要求的宏,应在 stddef.h 中找到。简而言之,offset 宏返回结构或联合的特定元素之前的偏移字节数。

宏的声明因供应商而异,并且取决于处理器体系结构。

浏览各种编译器,找到了一些清单示例声明。

// Keil 8051 compiler
#define offsetof(s,m) (size_t)&(((s *)0)->m)
// Microsoft x86 compiler (version 7)
#define offsetof(s,m) (size_t)(unsigned long)&(((s *)0)->m)
// Diab Coldfire compiler
#define offsetof(s,memb) \
    ((size_t)((char *)&((s *)0)->memb-(char *)0))
//Microsoft x86 compiler (version 2019)
#if defined _MSC_VER && !defined _CRT_USE_BUILTIN_OFFSETOF
    #ifdef __cplusplus
        #define offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
    #else
        #define offsetof(s,m) ((size_t)&(((s*)0)->m))
    #endif
#else
    #define offsetof(s,m) __builtin_offsetof(s,m)
#endif

无论实现如何,offset 宏采用两个参数。第一个参数是结构名称;第二个,结构元素的名称。

为了更好地理解offset宏的魔力,进一步来看定义的细节,宏中的各种运算符按顺序计算,以便执行以下步骤:

  • ((s *)0):  取整数零并将其转换为指向 s 的指针。
  • ((s *)0)->m: 引用指向结构成员 m 的指针。
  • &(((s *)0)->m):计算 m 的地址。
  • (size_t)&(((s *)0)->m): 将结果转换为适当的数据类型。

根据定义,结构本身驻留在地址 0。因此,指向的字段(上述步骤 3)的地址必须是结构开头的偏移量(以字节为单位)

结构体内嵌结构体的情况:


// Sytax.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
using namespace std;

int main()
{
	struct Demo{
		int a;
		char b;
		double c;
		char d[];
	};
	typedef struct
	{
		long  l;
		short s;

	} SBAR;

	typedef struct
	{
		int   i;
		float f;
		SBAR  b;

	} SFOO;
	/* Output is compiler dependent */

	printf("Offset of 'l' is %u \n", offsetof(SFOO, b.l));

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

	exit(EXIT_SUCCESS);

}

知识点:结构填充字节
大多数 16 位和更大的处理器要求在多字节(例如,16 位或 32 位)边界上对齐内存中的数据结构。有时,要求是绝对的,有时只是建议以获得最佳总线吞吐量。在后一种情况下,之所以提供灵活性,是因为设计人员认识到,您可能希望将内存访问时间与其他相互竞争的问题(如内存大小和传输能力(可能通过通信链路或直接内存访问)进行权衡。内存内容直接到具有不同对齐要求的另一个处理器。

还有一个相关的宏:

 7 // 根据"结构体(type)变量"中的"域成员变量(member)的指针(ptr)"来获取指向整个结构体变量的指针
 8 #define container_of(ptr, type, member) ({          \
 9     const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
10     (type *)( (char *)__mptr - offsetof(type,member) );})

扩展:

一般编译器是按照8字节对齐的。如果改变对齐字节,可以看到偏移有变化

#pragma pack(push) // 将当前pack设置压栈保存
#pragma pack(2)// 必须在结构体定义之前使用
	struct Demo{
		int a;//4,offset 0
		char b;//1,offset 4
		double c;//8,offset 6
		char d[];//1,offset 14
	};
#pragma pack(pop) // 恢复先前的pack设置

输出结果:

sizeof(struct Demo)=14
offsets: a=0; b=4; c=6 d=14

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/172099.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 最小二乘法详解_通俗是啥意思

    最小二乘法详解_通俗是啥意思本文转自https://blog.csdn.net/bitcarmanlee/article/details/51589143,谢谢原作者辛苦整理。若侵权,告知即删。最小二乘是每个上过大学的同学都接触过的概念与知识点(当然可能纯文科的同学没接触过,但是一般纯文科的同学也不会看这篇文章好像)。最小二乘理论其实很简单,用途也很广泛。但是每次说到最小二乘,总感觉差了点什么似的,好像对于最小二乘的前世…

    2022年8月30日
    3
  • Servlet和JSP的交互方式[通俗易懂]

    Servlet和JSP的交互方式[通俗易懂]文章目录Servlet和JSP的交互方式Servlet:jsp:1.表单:2.超链接超链接3.forward:获取参数值request.getParameter(“id”)处理乱码newString(request.getParameter(“name”).getBytes(“ISO8859_1″),”UTF-8”)Servlet和JSP的交互方式Servlet:1.request.getRequestDispatcher(“url”).forward(requsest,response);这个是

    2022年6月22日
    25
  • “永恒之蓝”病毒防护[通俗易懂]

    “永恒之蓝”病毒防护[通俗易懂]“永恒之蓝”勒索蠕虫涉及多个Windows系统服务的远程执行命令,恶意代码会扫描开放的445文件共享端口!只要开机的情况下,无需用户任何操作,就能控制你的电脑!SMB服务进行网络攻击的蠕虫病毒,简单的说就是:你局域网内如果有一台机器中了这个病毒,它会向整个网络传播,这个是非常可怕的!现在著名的勒索病毒和挖矿病毒都是利用这个漏洞进行传播,中了勒索病毒,就是交钱数据也回不来。不能全指望杀毒软…

    2022年10月16日
    0
  • Java 泛型

    Java 泛型

    2021年10月7日
    38
  • 深入编程之QQ盗号核心代码[通俗易懂]

    深入编程之QQ盗号核心代码[通俗易懂]经常有听到有朋友QQ被盗的消息,总感觉做出这种行为的人是可鄙的,不就是对QQ窗口进行监视,然后再是记录用户输入的号码和密码,认为没什么了不起。对于Windows核心编程,本人还是一只菜鸟,前一段时间把《Windows系统编程》粗略的看一边(当然重点地方仔细的看),由于对于C++有点基础,感觉学起来比较容易上手。但到了这两天真正实践的时候,遇到了各种各样的问题。即使一个小小的问题都足以让我…

    2022年6月26日
    67
  • java是值传递还是引用传递 知乎_按值调用和按引用调用

    java是值传递还是引用传递 知乎_按值调用和按引用调用最近整理面试题,整理到值传递、引用传递,到网上搜了一圈,争议很大。带着一脸蒙圈,线上线下查了好多资料。最终有所收获,所以分享给大家,希望能对你有所帮助。首先说下我的感受,这个题目出的很好,但是在Java中这个题目是有问题的(在下面我会解释)。并且,有很多结论是Java中只有值传递。我认为这样说不够严谨。当然如果针对Java语言本身来讲,Java中只有值传递,没有…

    2025年8月14日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号