使用 C 结构成员的连续内存

2023-12-02

在将其标记为重复之前,请先阅读问题。

所以这可能是一个潜在的非常愚蠢的问题,但它困扰着我。我从阅读以及许多其他问题中知道,由于编译器添加的填充,C 结构中的字段不能保证是连续的。例如,根据C标准:

13/在结构体对象中,非位域成员和位域所在的单元的地址按声明顺序递增。指向结构对象的指针经过适当转换后,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。结构对象内可能有未命名的填充,但不是在其开头。

我正在写一个类似于unix的程序readelf and nm只是为了好玩,它涉及到处理文件中特定偏移处的字节以读取某些值的大量工作。例如,目标文件的前 62 个字节包含“文件头”。文件头的字节 0x00-0x04 编码一个 int,而 0x20-0x28 编码一个指针等。但是,我注意到在 readelf.c 的原始实现中,程序员做了这样的事情:

首先,它们声明一个结构体(我们称之为 ELF_H),其中的字段与文件头中的内容相对应(即第一个字段是一个 int,就像文件头中的前 4 个字节一样,第二个字段是一个 char,因为字节 0x04 elf 标头中的 -0x05 编码字符等)。然后他们所做的就是将整个 elf 文件复制到内存中,并将指向该内存开头的指针键入 ELF_H 类型。就像是:

FILE *file = fopen('filename', rb);
void *start_of_file = malloc(/* size_of_file */);
fread(start_of_file, 1, /* size_of_file */,file);  // copies entire file into memory
ELF_H hdr = *(ELF_H) start_of_file;               // type case pointer to be of type struct and dereference

完成此操作后,只需使用结构体的成员变量访问标头的每个部分即可。因此,他们不是使用指针算术来获取字节 0x04 处的内容,而是只执行 hdr.member2 (在结构中,它是第二个成员,后面跟着第一个 int 成员)。

如果结构体中的字段不能保证连续,这意味着如何工作?

我能找到的最接近的答案是here但在该示例中,结构体的成员具有相同类型。在ELF_H中,它们是不同的类型。

先感谢您 :)


如果文件中的数据是从正在读取的形式的填充结构写入的,则填充是无关紧要的;该文件与内存表示一样包含填充。

确实,该标准并不是特别严格,编译器可以在 ELF 读取器结构中插入随机填充,而编写 ELF 的工具并不匹配。但实际上,“未命名填充”是为了对齐目的,所有主要编译器都有可预测的行为;他们通过填充来对齐字段以匹配其类型。所以int字段(在具有四字节的系统上int) 如果前一个字段未在四字节边界上结束,则前面有 1-3 个填充字节,char字段没有填充等。在这种情况下,我所知道的编译器都不会在前导之间插入填充int字段和以下char[2], 因为char无论如何都不需要对齐。

也可以使用非标准编译器扩展来防止填充来对齐结构中的字段,但如果您的结构定义永远不会有未对齐的字段,则没有必要(因为您总是将较小的字段放在较大的字段后面,或者因为您总是将较小的字段组合在一起以保持后续较大字段的对齐要求)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 C 结构成员的连续内存 的相关文章

  • 在两次之间每分钟执行一次 Cronjob

    我需要在 crontab 中每分钟运行一个 bash 脚本8 45am and 9 50am每天的 Code 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 8 home pull sh gt ho
  • 无法将 std::min 传递给函数,std::min 的副本有效

    Passing std min函数无法编译 我复制了 libcpp 声明std min进入我的源文件并且它可以工作 std 版本有什么问题 clang 和 gcc 也会发生同样的情况 在 Godbolt 上测试 https godbolt
  • 叮当错误?命名空间模板类的朋友

    以下代码在 clang 下无法编译 但在 gcc 和 VS 下可以编译 template
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • 在 ASP.NET MVC 中将模型从视图传递到控制器

    我正在 ASP NET MVC 中开发我的第一个应用程序 但遇到了一个我无法解决的问题 即使在阅读了整个互联网之后也是如此 因此 我有几个使用视图模型创建的视图 它们是报告 这些视图模型是根据用户选择标准填充的 我正在尝试构建一种接受模型并
  • while循环中的变量初始化

    我有一个可以分块读取文件的函数 public static DataObject ReadNextFile 数据对象看起来像这样 public DataObject public string Category get set And ot
  • C# 编译器数字文字

    有谁知道 C 编译器数字文字修饰符的完整列表 默认情况下 声明 0 使其成为 Int32 声明 0 0 使其成为 Double 我可以在末尾使用文字修饰符 f 来确保某些内容被视为 Single 例如像这样 var x 0 x is Int
  • 有什么方法可以重载 C# 中的扩展方法吗?

    我有以下模型模式 public abstract class PARENTCLASS public class CHILD A CLASS PARENTCLASS public static class EXTENSION public s
  • 在 C++11 中移出 stdpriority_queue 的元素

    最小的工作示例 include
  • 如何在win32中使用GetSaveFileName保存文件?

    我编写此代码是为了获取 fileName 来保存我的文件 include stdafx h include
  • 在 C# 中何时使用 ArrayList 而不是 array[]?

    我经常使用一个ArrayList而不是 正常 array 当我使用时 我感觉好像我在作弊 或懒惰 ArrayList 什么时候可以使用ArrayList在数组上 数组是强类型的 并且可以很好地用作参数 如果您知道集合的长度并且它是固定的 则
  • 用于连接 DataTable 上的动态列的动态 LINQ

    我目前遇到的情况不确定如何继续 我有两个从数据库填充的数据表 我还有一个可用的列名称列表 可用于将这两个数据表连接在一起 我希望编写一组 LINQ 查询 这些查询将 显示两个数据表中的行 内部联接 用于从一个数据表更新另一个数据表 显示一个
  • Xamarin - SignalR 挂在连接上

    我正在尝试将我的 Xamarin 应用程序连接到托管在 Azure 上的 SignalR 后端 我遇到的问题是每次我在 HubConnection 上调用 StartAsync 时 它都会挂起客户端并且请求永远不会完成 我尝试通过应用程序进
  • Resharper:IEnumerable 的可能多重枚举

    我正在使用新的 Resharper 版本 6 在我的代码中的几个地方 它给一些文本加了下划线 并警告我可能存在IEnumerable 可能的多重枚举 我理解这意味着什么 并在适当的情况下采纳了建议 但在某些情况下 我不确定这实际上是一个大问
  • 将错误代码映射到 C++ 中的字符串

    将错误代码从枚举映射到字符串的更有效方法是什么 在 C 中 例如 现在我正在做这样的事情 std string ErrorCodeToString enum errorCode switch errorCode case ERROR ONE
  • 使用多线程进行矩阵乘法?

    我应该使用线程将两个矩阵相乘 有两件事 当我运行程序时 我不断得到 0 我还收到消息错误 对于每个错误 它在粗体行上显示 警告 从不兼容的指针类型传递 printMatrix 的参数1 我尝试打印输出 还要注意 第一个粗体块 这是我解决问题
  • C# 中的 C/C++ 代码编译器

    在 C 中 我可以使用下面的代码编译 VB 和 C 代码 但无法编译 C C 代码 有什么办法可以做到这一点吗 C 编译器 public void Compile string ToCompile string Result null st
  • Linq.Select() 中的嵌套表达式方法调用

    I use Select i gt new T 每次手动点击数据库后将我的实体对象转换为 DTO 对象 以下是一些示例实体和 DTOS 用户实体 public partial class User public int Id get set
  • 这种尺寸对齐是如何工作的

    对于所提供的评论 我无法理解以下代码 这段代码的作用是什么 以及等效的代码是什么8 aligned segment size must be 4 aligned attr gt options ssize 3 Here ssize is o
  • 为什么表达式 a = a + b - ( b = a ) 在 C++ 中给出序列点警告?

    以下是测试代码 int main int a 3 int b 4 a a b b a cout lt lt a lt lt a lt lt lt lt b lt lt b lt lt n return 0 编译此命令会出现以下警告 gt g

随机推荐