offsetof(s,m)解析
https://www.cnblogs.com/jingzhishen/p/3696293.html
sizeof()用法汇总
sizeof()功能:计算数据空间的字节数
1.与strlen()比较
strlen()计算字符数组的字符数,以"\0"为结束判断,不计算为'\0'的数组元素。
而sizeof计算数据(包括数组、变量、类型、结构体等)所占内存空间,用字节数表示。
2.指针与静态数组的sizeof操作
指针均可看为变量类型的一种。所有指针变量的sizeof 操作结果均为4。
注意:int *p; sizeof(p)=4;
但sizeof(*p)相当于sizeof(int);
对于静态数组,sizeof可直接计算数组大小;
例:int a[10];char b[]="hello";
sizeof(a)等于4*10=40;
sizeof(b)等于6;
注意:数组做型参时,数组名称当作指针使用!!
void fun(char p[])
{sizeof(p)等于4}
char str[20]="0123456789";
int a=strlen(str); //a=10;
int b=sizeof(str); //而b=20;
char ss[] = "0123456789";
sizeof(ss) 结果 11 ===》ss是数组,计算到\0位置,因此是10+1
sizeof(*ss) 结果 1 ===》*ss是第一个字符
char ss[100] = "0123456789";
sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
strlen(ss) 结果是10 ===》strlen是个函数内部实现是用一个循环计算到\0为止之前
int ss[100] = "0123456789";
sizeof(ss) 结果 400 ===》ss表示在内存中的大小 100×4
strlen(ss) 错误 ===》strlen的参数只能是char* 且必须是以'\0'结尾的
char q[]="abc";
char p[]="a\n";
sizeof(q),sizeof(p),strlen(q),strlen(p); 结果是 4 3 3 2
一些朋友刚开始时把sizeof当作了求数组元素的个数,如今你应该知道这是不对的,那么应该怎么求数组元素的个数呢Easy,通常有下面两种写法:
1.int c1 = sizeof( a1 ) / sizeof( char ); // 总长度/单个元素的长度
2.int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 总长度/第一个元素的长度
Student stus[4]={
{"humingtao",24,99},
{"zhaoweisong",23,66},
{"chenfengchang",21,88},
{"zhuwenpeng",20,77}
数组长度 count = sizeof(stus)/sizeof(stus[0]
double* (*a)[3][6];
cout<<sizeof(a)<<endl; // 4 a为指针
cout<<sizeof(*a)<<endl; // 72 *a为一个有3*6个指针元素的数组
cout<<sizeof(**a)<<endl; // 24 **a为数组一维的6个指针
cout<<sizeof(***a)<<endl; // 4 ***a为一维的第一个指针
cout<<sizeof(****a)<<endl; // 8 ****a为一个double变量
offsetof(s,m)解析
const AVClass *class;
char *expr_str;
AVExpr *expr;
double var_values[VAR_VARS_NB];
enum AVMediaType type;
} SetPTSContext;
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
static const AVOption options[] = {
{ "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = FLAGS },
{ NULL }
};
&((s *)0)->m 是要取得类s中成员变量m的地址
由于这个类(或结构)的基址为0,这时m的地址当然就是m在s中的偏移了
我们许多人可能都使用过一些非挥发性的存储器,如常见的EEPROM。我们经常使用它们在存储一些系统的配置参数和设备信息。在所有的EEPROM中,通过串口访问的占了大多数。一般来说,对串口的访问都是按字节进行的,这使得我们不可避免会设计出下面的
接口去访问EEPROM的信息:
ee_rd(uint16_t offset, uint16_t nBytes, uint8_t * dest);
定义一个数据结构和一个指向这个数据结构的指针,并初始化这个指针为EEPROM的起始地址EEPROM_BASE.
| i | f | c | | | |...
----------------------------
| | | | | | |...
----------------------------
| | | | | | |...
----------------------------
...
----------------------------
{
int i;
float f;
char c;
} EEPROM;
a.容易使代码维护人员人误以为在ee_rd接口内部也存在EEPROM的数据结构。
b.当你编写一些自己感觉良好编译器不报错的代码,比如pEE->f = 3.2,你可能意想不到灾难将要来临。
c.这个接口没有很好地体现EEPROM所隐含的硬件特性。
比如成员f在EEPROM数据结构中的偏移量,这里为什么
要强制转化0,这是个有深度的问题,在后面也会详细说明*/
#define offsetof(type, f) ((size_t) \
((char *)&((type *)0)->f - (char *)(type *)0))
{
int i;
float f;
char c;
} EEPROM;
#define SIZEOF(s,m) ((size_t) sizeof(((s *)0)->m))
{
char pad[EEPROM_BASE];/*使数据结构的前EEPROM_BASE个字节填"空"*/
int i;
float f;
char c;
} EEPROM;
| | | | | | |...
----------------------------
...
---------------------------- <-EPPROM_BASE:0x00000a10
| i | f | c | | | |...
----------------------------
| | | | | | |...
----------------------------
...
这种映射使原本复杂的寄存器访问变得象访问普通的RAM地址一样方便。
在我们视频会议系统中,PowerPC 8250访问外部的ROM控制器(ROM controller)的
寄 存器就是通过这种方式实现的。ROM控制器所有的寄存器被映射到从I/O寄存器空间基地址0x10000000(IO_BASE)偏移 0x60000(ROMCONOffset)字节的一段内存。每个寄存器占用四个字节,并有一个数据结构与它们对应。比如控制ROM控制器工作状态的寄存 器对应数据结构ROMCON_ROM_CONTROL,配置PCI总线A的寄存器对应数据结构ROMCON_CONFIG_A,下面先看看这些数据结构的定义:
union {
struct {
UINT32 pad4:21; /* unused */
UINT32 pad3:2; /* reserved */
UINT32 pad2:5; /* unused */
UINT32 EnablePCIA:1;
UINT32 pad1:1; /* reserved */
UINT32 EnableBoot:1;
UINT32 EnableCpu:1; /*bit to enable cpu*/
} nlstruct;
UINT32 ConfigA;
} nlstruct4;
} nlunion;
} ROMCON_CONFIG_A, *PROMCON_CONFIG_A;
union {
struct {
UINT32 TransferComplete:1;
UINT32 pad3:1; /* unused */
UINT32 BondPad3To2:2;
UINT32 Advance:3;
UINT32 VersaPortDisable:1;
UINT32 pad2:1; /* unused */
UINT32 FastClks:1;
UINT32 pad1:7; /* unused */
UINT32 CsToFinClks:2;
UINT32 OeToCsClks:2;
UINT32 DataToOeClks:2;
UINT32 OeToDataClks:3;
UINT32 CsToOeClks:2;
UINT32 AddrToCsClks:2;
UINT32 AleWidth:2;
} nlstruct;
UINT32 RomControl;
} nlstruct4;
} nlunion;
} ROMCON_ROM_CONTROL, *PROMCON_ROM_CONTROL;
{
ROMCON_CONFIG_A ConfigA;
ROMCON_CONFIG_B ConfigB;
ROMCON_ROM_CONTROL RomControl;
...
}ROMCON, *PROMCON;
| | | | | | |...
----------------------------
| | | | | | |...
...
---------------------------- <-ROMCONOffset(ROMCON):0x60000
| | | | | | |...
---------------------------- <-ROMCON_ROM_CONTROL
...
----------------------------
估计有人可能会这样做:
事先定义成员RomControl(ROMCON中用ROMCON_ROM_CONTROL定义的实例)相对与ROMCON的偏移量,
void rom_write(dword_t* src, uint32_t* dest);
if(!tRomCtrl.nlunion.nlstruct.VersaPortDisable)
{
tRomCtrl.nlunion.nlstruct.VersaPortDisable = 1;
}
这样做确实可以达到访问相应寄存器的目的。但是,如果和ROM相关的寄存器很多,那么定义、记忆和管理那么多偏移量不是很不方便吗?到这里,如果你对前面关于offsetof还有印象的话,我想你可能会作下面的优化:
#define ROMCON_ADDR(m) (((size_t)IO_BASE+\
(size_t)ROMCONOffset+\
(size_t)offsetof(ROMCON,m))
dword_t* pReg=(dword_t*)ROMCON_ADDR(ConfigA);
if(!tRomCtrl.nlunion.nlstruct.VersaPortDisable)
{
tRomCtrl.nlunion.nlstruct.VersaPortDisable = 1;
}
通过前面的举例,你可能对如何使用offsetof已经不陌生了吧。offsetof对那些搞
C++ 的人可能很熟悉,因为offsetof类似于sizeof,也是一种系统操作符,你不用考虑它是怎么定义的。这个操作符offsetof的定义可以在 ANSI C 编译器所带的stddef.h中找到。在嵌入式系统里,不同开发商,不同架构处理器和编译器都有不同的offsetof定义形式:
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#define offsetof(s,m) (size_t)(unsigned long)&(((s *)0)->m)
#define offsetof(s,memb) ((size_t)((char *)&((s *)0)->memb-(char *)0))
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
((s *)0):强制转化成数据结构指针,并使其指向地址0;
((s *)0)->m:使该指针指向成员m
&(((s *)0)->m):获取该成员m的地址
(size_t)&(((s *)0)->m):转化这个地址为合适的类型
{
unsigned int a:3;
unsigned int b:13;
unsigned int c:16;
}foo;
offsetof(s,m)解析的更多相关文章
- 结构体指offsetof宏详细解析
1.#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER) (include/linux/stddef.h) ...
- Nginx的client_header_buffer_size和large_client_header_buffers学习
之前看到有人写的一篇关于nginx配置中large_client_header_buffers的问题排查的文章,其中提到: large_client_header_buffers 虽然也可以在serv ...
- 【C/C++编程入门学习】C语言结构体硬核玩法分享,一切皆是数据!
前言 对于结构体的应用太多了,今天这篇文章我主要为大家总结平时关于结构体的一些独特硬核小技巧,对于结构体更多优秀的编程表现,如果你对结构体的基础知识还不具备的话得回头看一下专栏教程或者自己找本书籍学习 ...
- Python2 基本数据结构源码解析
Python2 基本数据结构源码解析 Contents 0x00. Preface 0x01. PyObject 0x01. PyIntObject 0x02. PyFloatObject 0x04. ...
- Nginx学习之二-配置项解析及编程实现
在开发功能灵活的Nginx模块时,需要从配置文件中获取特定的信息.不过,我们并不需要再编写一套读取配置的系统,Nginx已经为用户提供了强大的配置项解析机制,同时还支持“-s reload”命令,可以 ...
- Nginx学习——http配置项解析编程
http配置项解析编程 配置config ngx_addon_name=ngx_http_mytest_module HTTP_MODULES="$HTTP_MODULES ngx_http ...
- nginx源代码分析--配置文件解析
ngx-conf-parsing 对 Nginx 配置文件的一些认识: 配置指令具有作用域,分为全局作用域和使用 {} 创建其他作用域. 同一作用域的不同的配置指令没有先后顺序:同一作用域能否使用同样 ...
- typeof, offsetof 和container_of
要理解Linux中实现的双向循环链表("侵入式"链表),首先得弄明白宏container_of. 本文尝试从gcc的关键字typeof和宏offsetof入手,循序渐进地剖析宏co ...
- C语言之浅析网络包解析
1.这几天研究skynet中的 lua-netpack.c 中的解析数据包过程.于是把lua部分去掉,修改了一些接口,留下解包相关的代码.再结合云风写的网络代码的例子, 写了一个最简单形式的客户端封包 ...
随机推荐
- WPF DesiredSize & RenderSize
DesiredSize DesiredSize介绍 关于DesiredSize的介绍,可以查看最新微软文档对DesiredSize的介绍 DesiredSize,指的是元素在布局过程中计算所需要的大小 ...
- 使用微软PinYinConverter查询汉字拼音
通过汉字,如何查询拼音? 微软有相应的DLL可直接使用 引用方式 Nuget包管理安装 DLL下载后,引用 可以从微软的网站上下载相关文字处理的类库,下载地址如下: http://download.m ...
- Java开发笔记(五十一)多态的发生场景
江湖上传闻,面向对象之所以厉害,是因为它拥有封装.继承与多态三项神技,只要三板斧一出,号令天下谁敢不从.前面费了老大的劲才讲清楚封装和继承,那么多态又是怎样的神乎其神呢?下面先通过一个简单的例子来说明 ...
- Android安全–加强版Smali Log注入
有的时候我们需要注入smali调用Log输出,打印字符串的值. 比如说: 如果我们要打印下面v1的值. new-instance v1, Ljava/lang/String; const-string ...
- Java学习笔记之——集合
集合是类,用来存储多个数据,有属性.方法 集合是一个可变数组,保存相同元素并且长度可变 1. 体系 (1)Collection:存储一个一个的值 Iterable: Iterable<T> ...
- vue中computed计算属性与methods对象中的this指针
this 指针问题 methods与computed中的this指针 应该指向的是它们自己,可是为什么this指针却可以访问data对象中的成员呢? 因为new Vue对象实例化后data中的成员和c ...
- 后端开发者的Vue学习之路(四)
目录 上节内容回顾: npm 介绍 安装 常用命令: 补充: 基于npm的Hello World 项目结构分析 用法迁移 小提醒 ES6语法 知识补充 单文件组件 使用注意: 路由 开启路由 定义路由 ...
- qduoj前端二次开发简略流程
为缩减篇幅,已略去nodejs.git等软件安装操作,若有疑问请搜索相关教程. 为区分win和ubuntu的命令,作如下约定: $ cd //以$标记win下命令 # cd //以#标记linux命令 ...
- 如何解决angular不自动生成spec.ts文件
"schematics":{ "@schematics/angular:component": { "styleext": ...
- 谷歌浏览器扩展程序manifest.json参数详解
{ // Required "manifest_version": 2, // manifest编写规范版本,目前主流2 "name": "My Ex ...