文档章节

关于c语言结构体成员变量访问方式的一点思考

算法与编程之美
 算法与编程之美
发布于 2013/06/27 11:25
字数 1150
阅读 5608
收藏 36
点赞 2
评论 11

前言

 

上篇博文(关于c语言结构体偏移的一点思考)对c语言中结构体偏移做了一些思考,发现博文中还有一些小的问题,没有描述的足够清楚,所以才萌生了本篇博文的想法。

为什么不直接将本篇博文作为上篇博文的一个“注”呢?主要有以下方面的原因,一是使用一篇独立的博文能够更好的阐述问题,从而彻底的理解它;二是上篇博文的篇幅已经比较长,考虑到读者的耐心,所以一篇博文不适合过长的篇幅;三是这个问题可以作为一个独立的主题来探讨,方便查阅;最后本着单一职责的原则,每篇博文讨论一个特定的主题,对于主题的粒度大小,可酌情考虑。

那么本篇博文主要探讨什么问题呢?从本文的标题我们可以看到,本文主要探讨的是c语言中关于结构体成员变量的访问方式。访问结构体成员变量?如此简单的问题,有什么可以思考的呢?很纳闷也很奇怪。既然这样,那就带着这个奇怪的问题继续阅读吧。

示例

我们的探讨还是从一个简单的示例开始:

已知结构体类型定义如下:

struct node_t {
    char a;
    int b;
    int c;
};

且结构体1Byte对齐:

#pragma pack(1)

接下来我们探讨几种访问该结构体成员变量c的方式:

 

情形1

如果程序中定义了一个struct node_t类型的变量node如下:

struct node_t node;

那么我们就可以直接通过下面的方式来访问成员变量c:

node.c

 


 

情形2

如果程序中定义了一个指向struct node_t类型的指针p_node如下:

struct node_t node;
struct node_t *p_node = &node;

或者在堆上分配了一块类型为struct node_t的内存如下:

struct node_t *p_node= (struct node_t *)malloc(sizeof(struct node_t));

那么我们就可以使用下面的方式来访问成员变量c:

p_node -> c;

 

情形3

上述两种访问方式都是比较常见的,也是大家所熟悉的,下面我们来探讨一种大家不是特别熟悉也不是很常见的情形:

如果程序中只给定了一个内存地址数值addr_node,且该地址addr_node起始的一段内存,指向一块类型为struct node_t的内存,addr_node声明如下:

unsigned long addr_node;

此时,我们如何根据这块内存地址来访问成员变量c呢?

 

由于我们知道了该结构体的起始地址addr_node,所以我们对其进行强制类型转换,从而得到一个指向该结构体的指针p_node:

struct node_t *p_node = (struct node_t *)addr_node;

接下来我们就可以通过情形2的方式来访问成员变量c了;

 

情形3要传达的意思是,我们可以通过一个具体的内存地址数值来访问我们的结构体成员变量;

关于情形3的一点说明

为什么特地的指出情形3,因为我们上一篇博文关于c语言结构体偏移的一点思考中使用了类似的用法:

 

((struct node_t *)0)->c

 

我们通过内存地址0来访问结构体struct node_t成员变量c,但这里面有几点需要说明一下:

1. 我们并未对内存地址0做过任何内存相关操作,如解引用、赋值等,即内存地址编号0开始的一段内存无任何变化;

2. 我们只是利用了编译器的特性来帮助我们计算结构体的偏移,仅仅是利用了编译器的特性来计算而已;

3. 善于利用编译器的一些特性来优化我们的程序或系统;

结论

本文主要介绍了c语言中关于访问结构体成员变量的几种方式,并对通过内存地址数值直接访问结构体成员变量做了说明,解释了上篇博文中可能产生疑问的一个问题。

如果您对算法或编程感兴趣,欢迎扫描下方二维码并关注公众号“算法与编程之美”,和您一起探索算法和编程的神秘之处,给您不一样的解题分析思路。

 

© 著作权归作者所有

共有 人打赏支持
算法与编程之美
粉丝 281
博文 80
码字总数 92711
作品 0
成都
程序员
加载中

评论(11)

算法与编程之美
算法与编程之美

引用来自“ghui_dev”的评论

说得很透彻,很好 我也想知道container_of的怎么样的79
谢谢鼓励,我会继续创作更多优质博客。
ghui_dev
ghui_dev
说得很透彻,很好 我也想知道container_of的怎么样的79
算法与编程之美
算法与编程之美

引用来自“我土鳖”的评论

更正一下,在C99里解引用null是未定义行为,详情请参见此贴一楼及一楼附属的讨论内容: http://stackoverflow.com/questions/7897877/how-does-the-c-offsetof-macro-work

非常感谢你的建议,^_^
我土鳖
更正一下,在C99里解引用null是未定义行为,详情请参见此贴一楼及一楼附属的讨论内容: http://stackoverflow.com/questions/7897877/how-does-the-c-offsetof-macro-work
我土鳖
那个帖子还提到,说当 (type *)0->name 这一句出现的时候,有些笨拙的编译器就会直接产生一个内存访问(换句话说,没做优化),所以是有一定风险的。
我土鳖

引用来自“justin_cn”的评论

引用来自“我土鳖”的评论

引用来自“justin_cn”的评论

引用来自“我土鳖”的评论

OFFSET_OF宏?

这是我在上篇博文中自定义的,man 3 offsetof这个函数其实也是一个宏,不过我没有具体的看他宏的定义

GCC已经将offsetof视为内嵌函数了。LLVM/Clang好像也是这样。

gcc的确是这样,我刚才查了下资料,定义如下
#define __builtin_offsetof(type, name) ((__SIZE_TYPE__)&((type *)(0ul))->name)
和我博客中说道的是一样的。

之前在stackoverflow看到过一个讨论,说这样用0不太合适什么的,所以GCC干脆些成了个内嵌函数。LZ不妨也介绍介绍container_of宏。
算法与编程之美
算法与编程之美

引用来自“我土鳖”的评论

引用来自“justin_cn”的评论

引用来自“我土鳖”的评论

OFFSET_OF宏?

这是我在上篇博文中自定义的,man 3 offsetof这个函数其实也是一个宏,不过我没有具体的看他宏的定义

GCC已经将offsetof视为内嵌函数了。LLVM/Clang好像也是这样。

gcc的确是这样,我刚才查了下资料,定义如下
#define __builtin_offsetof(type, name) ((__SIZE_TYPE__)&((type *)(0ul))->name)
和我博客中说道的是一样的。
我土鳖

引用来自“justin_cn”的评论

引用来自“我土鳖”的评论

OFFSET_OF宏?

这是我在上篇博文中自定义的,man 3 offsetof这个函数其实也是一个宏,不过我没有具体的看他宏的定义

GCC已经将offsetof视为内嵌函数了。LLVM/Clang好像也是这样。
算法与编程之美
算法与编程之美

引用来自“我土鳖”的评论

OFFSET_OF宏?

这是我在上篇博文中自定义的,man 3 offsetof这个函数其实也是一个宏,不过我没有具体的看他宏的定义
我土鳖
OFFSET_OF宏?
关于c语言结构体偏移的一点思考

前言 相信大家在c语言程序开发的过程一定都使用过结构体,那么不知你对结构体中成员变量偏移这块是如何理解的?本文将和大家一起分享下,本人最近关于c语言中结构体偏移的一些思考和总结。 ...

算法与编程之美 ⋅ 2013/06/25 ⋅ 23

深入理解C语言结构体成员变量内存分配

欢迎点击「算法与编程之美」↑关注我们! 本文首发于微信公众号:"算法与编程之美",欢迎关注,及时了解更多此系列博客。 1 问题描述 在学习C语言的时候,我们都会频繁的接触到结构体,使用结...

算法与编程之美 ⋅ 04/05 ⋅ 0

SWIG入门4: C/C++初级特性2

1 structure 我看来,structure乃是封装之源。SWIG对于strucure的封装非常自然。自然的意思就是,C语言里怎么用PYTHON就怎么用。水里水里来,火里火里去。不过第一个问题就是,PYTHON作为面向...

costaxu ⋅ 2012/08/18 ⋅ 1

C语言中结构体在函数中的应用

一、结构体与函数参数 结构体作函数参数可分为传值与传指针。 1.传值时结构体参数会被拷贝一份,在函数体内修改结构体参数成员的值实际上是修改调用参数的一个临时拷贝的成员的值,这不会影...

学习环境 ⋅ 2015/09/22 ⋅ 0

关于面向过程编程的一些思考

关于面向过程编程与指针的一些思考 长期以来,虽然有C语言的基础,但对C的使用主要停留在书面例子的基础上,没有复杂的功能和调用关系,因此,对面向过程的理解并不深刻。而使用java、js编写...

AlexTuan ⋅ 2016/12/07 ⋅ 0

C语言结构体的字节对齐原则

C语言结构体的字节对齐原则 Mindy2017-03-3046 阅读 结构C语言字节对齐 为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,...

Mindy ⋅ 2017/03/30 ⋅ 0

面向对象编程的面向过程表示:c java go

题目就这么抽象~。~其实一点都不抽象,老师以前也说过吧,面向对象就是建立在面向过程的基础上的。 下面这些主要是能让大家吸收一些较新鲜的编程思路,对于嵌入式编程大有裨益,对理解面向对...

fbf ⋅ 2014/01/15 ⋅ 0

C语言基础-13-结构体

C语言的核心部分都说得七七八八了,相信大家已经对C语言的基本数据类型(charintfloat)、数组、指针都很熟悉了,今天来学习C语言中另外一种数据类型:结构体。在iOS开发中,结构体是经常用到的...

Corwien ⋅ 2016/03/16 ⋅ 0

Objective-C高级编程之block篇

block是C语言的一项重要的特性。在很多其他计算机语言中都有类似的概念,比如lamda表达式,闭包等。那么block是什么?简而言之,block是带有自动变量的匿名函数。本文将以这句话展开,对blo...

凝望向北 ⋅ 2017/04/24 ⋅ 0

c语言结构体用法

结构(struct) 结构是由基本数据类型构成的、并用一个标识符来命名的各种变量的组合。 结构中可以使用不同的数据类型。 1. 结构说明和结构变量定义 在Turbo C中, 结构也是一种数据类型, 可以使...

长平狐 ⋅ 2012/09/03 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java Web如何操作Cookie的添加修改和删除

创建Cookie对象 Cookie cookie = new Cookie("id", "1"); 修改Cookie值 cookie.setValue("2"); 设置Cookie有效期和删除Cookie cookie.setMaxAge(24*60*60); // Cookie有效时间 co......

二营长意大利炮 ⋅ 53分钟前 ⋅ 0

【每天一个JQuery特效】淡入淡出显示或隐藏窗口

我是JQuery新手爱好者,有时间就练练代码,防止手生,争取每天一个JQuery练习,在这个博客记录下学习的笔记。 本特效主要采用fadeIn()和fadeOut()方法显示淡入淡出的显示效果显示或隐藏元...

Rhymo-Wu ⋅ 57分钟前 ⋅ 0

Spring JDBC使用方法

普通实现: 1、创建数据表customer。 可以使用任何数据库实现,在项目中要引入相应数据库驱动包并配置相应数据库连接。 2、创建Customer pojo。 Customer类的属性对应数据库的属性,除了为每...

霍淇滨 ⋅ 今天 ⋅ 0

Contos 7 安装Jenkins

Jenkins是一款能提高效率的软件,它能帮你把软件开发过程形成工作流,典型的工作流包括以下几个步骤 开发 提交 编译 测试 发布 有了Jenkins的帮助,在这5步中,除了第1步,后续的4步都是自动...

欧虞山 ⋅ 今天 ⋅ 0

revel

revel install go get github.com/revel/revelgo get github.com/revel/cmd create new app revel new git.oschina.net/zdglf/myapp run app revel run git.oschina.net/zdglf/myapp ot......

zdglf ⋅ 今天 ⋅ 0

49. Group Anagrams - LeetCode

Question 49. Group Anagrams Solution 思路:维护一个map,key是输入数组中的字符串(根据字符排好序) Java实现: public List<List<String>> groupAnagrams(String[] strs) { Map<Strin......

yysue ⋅ 今天 ⋅ 0

spring Email

使用spring发Email其实就是使用spring自己封装携带的一个javamail.JavaMailSenderImpl类而已。这个类可以当一个普通的java对象来使用,也可以通过把它配置变成spring Bean的方式然后注入使用...

BobwithB ⋅ 今天 ⋅ 0

spark 整理的一些知识

Spark 知识点 请描述spark RDD原理与特征? RDD全称是resilient distributed dataset(具有弹性的分布式数据集)。一个RDD仅仅是一个分布式的元素集合。在Spark中,所有工作都表示为创建新的...

tuoleisi77 ⋅ 今天 ⋅ 0

思考

时间一天天过感觉自己有在成长吗?最怕的是时光匆匆而过,自己没有收获!下面总结下最近自己的思考。 认识自己 认识另一个自己,人们常说要虚心听取别人意见和建议。然而人往往是很难做到的,...

hello_hp ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部