

文章目录
在结构体章节,我们掌握了结构体的基本使用,但是现在我要你去计算一个结构体的大小,你会怎么做呢?
c1、c2、i三个成员变量,那此时分别去计算它们两个结构体的大小, 最后的结果会是多少呢?会是一样的吗struct S1 {
char c1;
int i;
char c2;
};
struct S2 {
char c1;
char c2;
int i;
};
int main(void)
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
c1的类型为【char】,是1个字节;i的类型是【int】,是4个字节c2的类型为【char】,是1个字节;1 + 4 + 1 = 6B,可事实呢,原不止这些。。。
offsetof,它可以用来计算结构体成员相对于起始位置的偏移量
它的第一个参数是结构体类型,第二个参数是结构体成员
printf("%d\n", offsetof(struct S1, c1));
printf("%d\n", offsetof(struct S1, i));
printf("%d\n", offsetof(struct S1, c2));

为什么会出现上面这样的现象呢?对于结构体内存对齐的规则是怎样,让我们继续看下去👇
知晓了上面这些规则后,我们再来回顾一下上面这个结构体的大小该如何计算
ss,它的起始地址就从0开始,所以根据第一条规则,第一个成员变量在与结构体变量偏移量为0的地址处,而且它的类型还是char,所以只占1个内存单元
i,其为整型所以在内存中就需要存储4个字节的大小,此时便要拿其和VS下默认对齐数8去进行比较,取较小的值4i是从4的位置开始放的,中间空出来的位置就不会再放置其他成员变量了,那么这个3个空间也就浪费了
c2,char类型的变量为1个字节,和8比较取小就是1,那就要将其放到1整数倍的地址处,那其实任何空间都是可以的,直接放到这个【8】的位置就行

看完了,这个结构体后,还记得结构体S2吗,我再来讲一道,当然你也可以试着自己写写画画看👈
c1放在这个与结构体变量偏移量为0的地址处,而且它的类型还是char,所以只占1个内存单元
char所占的字节为1B,与8去进行比较一下就可以知道1来得小,那我们直接放在偏移处为1的地方就可以了,此时在内存中也只占了2个字节

通过上面两道例题的讲解,相信你对如何去计算结构体大小一定有了一个自己的认识,接下去就让我们趁热打铁🔥来做两道题目再练一练,看看自己是否真的掌握了
你可以先试着自己做一做,然后和我对一下是否正确
struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3));
【分析】:
double类型的数据在内存中占8个字节,所以一直占用偏移处为7的地方
char,所以在内存中占用1个字节,那直接放在偏移量为8的地址处即可

运行结果如下:

也可以通过【offsetof】来验证一下

接下去再来做一道练习,涉及结构体嵌套的问题,对应的需要使用到规则4,忘记了可以翻上去看看👈
struct S3
{
double d;
char c;
int i;
};
struct S4
{
char c1;
struct S3 s3; //成员变量为另一个结构体
double d;
};
因为本题的结构体比较大,所以就标出4的整数倍所在的地址
char,所以只占一个字节的空间

double类型的数据在内存中占8个字节,所以一直到31的地址处
运行结果如下:

可以通过【offsetof】再来验证一下

经过了两道例题和两道练习题的训练,相信你对如何计算结构体的大小一定是心中有数了,但在阅读的过程中你是否有疑惑为什么会存在这个【结构体内存对齐】呢?有什么实际意义吗?
c和i,然后要在内存中存储它们,我分为了两种,一个是【无内存对齐】,呈现的是紧密存放;一个是【内存对齐】,需要考虑到最大对齐数c,但是若要全部读取完i,就还需要再读取一次,那访问到所有的成员变量就需要两次;c和i互不干扰,此时再看到成员变量i,从它的初始地址处开始读取,一次读4个字节,那么读1次就刚刚好可以读完这个变量了,而不是像上面那样还需要再读一次
总体来说:
结构体的内存对齐是拿空间来换取时间的做法
了解了为什么会存在内存对齐之后,我们再回到一开始的这两个结构体,你是否有想过为什么两个结构体的成员变量都一模一样但是大小却是一个【12】,一个【8】呢?
struct S1 {
char c1;
int i;
char c2;
};
struct S2 {
char c1;
char c2;
int i;
};
之前我们见过了 #pragma 这个预处理指令
#pragma comment,用来链接函数的静态库。这里我们再次使用,可以改变我们的默认对齐数
#pragma pack(1)就可以设置默认对齐数为1,#pragma pack()就可以取消设置的默认对齐数,还原为默认。到它为止的默认对齐数还是被修改后的对齐数#pragma pack(1)//设置默认对齐数为1
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct S1));
return 0;
}

运行结果如下:

可以通过【offsetof】再来验证一下

结论:
在上面的每一个结构体计算后,我都使用到了
offsetof这个宏,和我画出来的内存分布图完全就是一致的,那它的原理到底是怎样的呢?马上来探究一下🔍
曾经有一年的百度笔试题就考到了有关offsetof 的实现原理
👉 【原题】:写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
那要如何去实现呢?如果对宏不是很了解的读者可以看看详解程序环境和预处理
我们通过上面的结构体S1进行讲解。列出3个成员变量放置的初始地址,其实【offsetof】计算的也就是每个变量在内存中的起始地址相较于首地址偏移了多少,那将它们进行一个相减就可以得出0、4、8这三个结果

c1这块地址设置为0,那么
&c1 - 0&i - 0&c2 - 0
知道了上面这些我们就可以使用【宏】来实现每个成员变量偏移量的计算了
#define OFFSETOF(m_type, m_name) (int)&(((m_type *)0)->m_name)
m_type是结构体变量;m_name是结构体成员
#define OFFSETOF(m_type, m_name) (m_type *)0
printf("%d\n", OFFSETOF(struct S1, c1));
m_name#define OFFSETOF(m_type, m_name) ((m_type *)0)->m_name
#define OFFSETOF(m_type, m_name) &(((m_type *)0)->m_name)
#define OFFSETOF(m_type, m_name) (int)&(((m_type *)0)->m_name)
下面是流程图:

下面是运行结果:

结构体怎么对齐? 为什么要进行内存对齐?
如何让结构体按照指定的对齐参数进行对齐?能否按照3、4、5即任意字节对齐?
#pragma pack(3)便可以将默认对齐数修改为3,其他的也是同理,因为结构体默认对齐数发生了变化,此时就会导致结构体大小发生变化最后来总结一下本文所学习的内容📖
offsetof(),但是不清楚原理是什么👉这不,百度笔试题就考到了,于是我们就去自己通过一个宏实现了一下这个偏移量的求解,虽然过程很复杂,但是在我一步步的细讲下,相信聪明的你一定有所理解😁在理解了结构体内存对齐的各方面之后,面对两道面试题也是毫不畏惧💪可以发现仅仅是非常小的一个知识点,我却讲解了近万字,因为这是校招的笔试面试中C语言这一块的热门考点,如果有投递相关岗位的同学一定要搞清楚每一步🥰

作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
您将如何构建一个简单的Sinatra应用程序?我正在制作,我希望该应用具有以下功能:“应用程序”更像是一个包含所有信息的管理仪表板。然后另一个应用程序将通过REST访问信息。我还没有创建仪表板,只是从数据库中获取东西session和身份验证(尚未实现)您可以上传图片,其他应用可以显示这些图片我已经使用RSpec创建了一个测试文件通过Prawn生成报告目前的设置是这样的:app.rbtest_app.rb因为我实际上只有应用程序和测试文件。到目前为止,我已经将Datamapper用于ORM,将SQLite用于数据库。这是我的第一个Ruby/Sinatra项目,所以欢迎任何和所有建议-我应
你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p
我想编写一个ruby脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"
这会导致Ruby出现内存问题吗?我知道如果大小超过10KB,Open-URI会写入TempFile。但是HTTParty会在写入TempFile之前尝试将整个PDF保存到内存吗?src=Tempfile.new("file.pdf")src.binmodesrc.writeHTTParty.get("large_file.pdf").parsed_response 最佳答案 您可以使用Net::HTTP。参见thedocumentation(特别是标题为“流媒体响应机构”的部分)。这是文档中的示例:uri=URI('http://e
对于我正在编写的Rails3应用程序,我正在考虑从本地文件系统上的XML、YAML或JSON文件中读取一些配置数据。重点是:我应该把这些文件放在哪里?Rails应用程序中是否有用于存储此类内容的默认位置?附带说明一下,我的应用程序部署在Heroku上。 最佳答案 我经常做的是:如果文件是通用配置文件:我在目录/config中创建一个YAML文件,每个环境有一个上层key如果我为每个环境(大项目)创建一个文件:我为每个环境创建一个YAML并将它们存储在/config/environments/然后我在加载YAML的地方创建了一个初始化
在我的mac上安装几个东西时遇到这个问题,我认为这个问题来自将我的豹子升级到雪豹。我认为这个问题也与macports有关。/usr/local/lib/libz.1.dylib,filewasbuiltfori386whichisnotthearchitecturebeinglinked(x86_64)有什么想法吗?更新更具体地说,这发生在安装nokogirigem时日志看起来像:xslt_stylesheet.c:127:warning:passingargument1of‘Nokogiri_wrap_xml_document’withdifferentwidthduetoproto