我什么时候应该按值传递或返回结构体?

2024-04-25

在 C 中,结构体可以按值传递/返回,也可以按引用(通过指针)传递/返回。

普遍的共识似乎是前者可以应用于小型结构,在大多数情况下不会受到惩罚。看在任何情况下,直接返回结构是一种好的做法吗? https://stackoverflow.com/a/7550578 and 在 C 中按值传递结构而不是传递指针有什么缺点吗? https://stackoverflow.com/a/161845/5036089

从速度和清晰度的角度来看,避免取消引用都是有益的。但什么算作small?我想我们都同意这是一个小结构:

struct Point { int x, y; };

我们可以相对不受惩罚地传递值:

struct Point sum(struct Point a, struct Point b) {
  return struct Point { .x = a.x + b.x, .y = a.y + b.y };
}

还有 Linux 的task_struct是一个大结构体:

https://github.com/torvalds/linux/blob/b953c0d234bc72e8489d3bf51a276c5c4ec85345/include/linux/sched.h#L1292-1727 https://github.com/torvalds/linux/blob/b953c0d234bc72e8489d3bf51a276c5c4ec85345/include/linux/sched.h#L1292-1727

我们希望不惜一切代价避免放入堆栈(尤其是那些 8K 内核模式堆栈!)。但中等的又如何呢?我认为小于寄存器的结构就可以了。但这些呢?

typedef struct _mx_node_t mx_node_t;
typedef struct _mx_edge_t mx_edge_t;

struct _mx_edge_t {
  char symbol;
  size_t next;
};

struct _mx_node_t {
  size_t id;
  mx_edge_t edge[2];
  int action;
};

哪个最好经验法则用于确定结构体是否足够小,可以安全地按值传递它(除非出现某些深度递归等情有可原的情况)?

最后请不要告诉我我需要分析。当我太懒/不值得进​​一步调查时,我要求使用启发式方法。

编辑:根据迄今为止的答案,我有两个后续问题:

  1. 如果该结构实际​​上是怎么办smaller而不是指向它的指针?

  2. 如果浅复制是所需的行为(被调用的函数无论如何都会执行浅复制)怎么办?

编辑:不知道为什么这被标记为可能的重复,因为我实际上链接了我的问题中的其他问题。我要求澄清什么是smallstruct 并且我很清楚大多数时候结构应该通过引用传递。


在小型嵌入式架构(8/16 位)上 --always通过指针传递,因为重要的结构不适合如此小的寄存器,并且这些机器通常也缺乏寄存器。

在类 PC 架构(32 和 64 位处理器)上——只要按值传递结构就可以sizeof(mystruct_t) <= 2*sizeof(mystruct_t*)并且该函数没有很多(通常超过 3 个机器字的)其他参数。在这些情况下,典型的优化编译器将传递/返回寄存器或寄存器对中的结构。然而,在 x86-32 上,由于 x86-32 编译器必须处理异常的寄存器压力,因此应该对这个建议抱有很大的怀疑——由于寄存器溢出和填充的减少,传递指针可能仍然更快。

另一方面,在类 PC 上按值返回结构遵循相同的规则,除了当通过指针返回结构时,要填充的结构应该是通过了也可以通过指针 - 否则,被调用者和调用者必须就如何管理该结构的内存达成一致。

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

我什么时候应该按值传递或返回结构体? 的相关文章

  • 列出 C 常量/宏

    有没有办法使GNU C 预处理器 cpp 或其他一些工具 列出给定点上的所有可用宏及其值C file 我正在寻找特定于系统的宏 同时移植一个已经精通 UNIX 的程序并加载一堆稀疏的 UNIX 系统文件 只是想知道是否有比寻找定义更简单的方
  • ServiceStack 验证并不总是触发

    因此 我尝试使用 RavenDB 和 ServiceStack 构建端到端集成测试套件 但遇到了一个非常奇怪的问题 即验证无法对某些请求运行 这真的很奇怪 我不确定我做错了什么 我正在使用 NCrunch 有时测试通过 有时失败 希望这是一
  • 读取进程的进程内存不会返回所有内容

    我正在尝试扫描第三方应用程序的内存 我已经查到地址了 现在是在0x0643FB78 问题是 从那以后我就再也爬不上去LPMODULEENTRY32 gt modBaseAddr is 0x00400000 and LPMODULEENTRY
  • 使 C++ 在模板函数的特定实例化上编译失败

    我正在开发一个具有模板功能的项目 如下所示 template
  • 如何使用C#检测IIS版本?

    如何使用C 检测IIS版本 更新 我的意思是来自 winapp 实际上该场景是开发一个自定义安装程序 想要检查已安装 IIS 的版本以调用适当的 api 在这里找到了答案 链接文本 http forums iis net p 1162404
  • 在主窗体上使用 BeginInvoke 调用的网络任务未执行

    我使用 Visual Studio 2013 构建了一个具有单个表单的 C 应用程序 并且该应用程序有两个更新屏幕的例程 更新屏幕的例程需要在主线程上运行 因此我自己的线程 不与屏幕交互 在需要更新时调用主窗体上的 BeginInvoke
  • 未初始化成员的警告在 C++11 上消失

    我编译这个简单的程序 include
  • 如何在cmake中添加cuda源代码的定义

    我使用的是 Visual Studio 2013 Windows 10 CMake 3 5 1 一切都可以使用标准 C 正确编译 例如 CMakeLists txt project Test add definitions D WINDOW
  • 如何吞咽……有具体原因的异常

    在这个方法中 public static void Detach try using var master new DataContext Data Source LocalDB MSSQLLocalDB Initial Catalog m
  • Oracle ODP.Net 与实体框架 6 - 从表视图中选择时出现 ORA-00955

    我创建了两个应用程序 第一个使用 ODP Net 另一个没有实体 效果很好 static void Main string args OracleConnection con new OracleConnection using conne
  • C# 字典循环增强

    我有一本包含大约 100 万个条目的字典 我不断地循环字典 public void DoAllJobs foreach KeyValuePair
  • 只允许在 datagridview 单元格中键入一些字符

    有没有办法只将某些字符添加到 datagridview 单元格中 像 1234567890 据我所知 您可以使用两种方法来实现此目的 第一个 我认为最好的 是使用 CellValidating 事件DataGridView并检查输入的文本是
  • 企业库 CacheFactory.GetCacheManager 抛出空引用

    我正在尝试将使用 1 1 版本的企业库缓存块的应用程序转换为 2 0 版本 我认为我真正遇到的问题是不同 EntLib 部分的配置被分成几个文件 显然 这曾经是由ConfigurationManager 部分处理程序 但现在已经过时 取而代
  • BackgroundWorker 如何决定在哪个线程上运行 RunWorkerCompleted 处理程序?

    我试图弄清楚 BGW 在工作完成后如何决定运行 RunWorkerCompleted 处理程序的线程 我的初始测试使用 WinForm 应用程序 在 UI 线程上 我开始bgw1 RunWorkerAsync 然后我尝试开始bgw2 Run
  • List.Except 不起作用

    我尝试减去 2 个列表 如下代码所示 assignUsers已获得 3 条记录assignedUsers有 2 行 后Except方法我仍然得到 3 行 尽管我应该得到 1 条记录 因为 2 行assignedUsers类似于assignU
  • 在 C# 中同步闪烁标签

    我创建了一个BlinkingLabel类 源自Forms Label 其中有一个Forms Timer这允许我启用和禁用闪烁效果 我创建了 4 个标签BlinkingLabel类型 我的问题是 如果所有 4 个标签在不同时间闪烁 则闪烁效果
  • 显示具有相同节点值的多个 XML 数据条目

    我有一个 XML 文档 其中包含课程信息 如下所示
  • STL迭代器是否保证集合更改后的有效性?

    假设我有某种集合 并且我在它的开头获得了一个迭代器 现在假设我修改了该集合 无论集合或迭代器的类型如何 我仍然可以安全地使用迭代器吗 为了避免混淆 以下是我讨论的操作顺序 获取集合的迭代器 修改集合 显然 不是其中的元素 而是集合本身 使用
  • SQL 注入在 winform 中有效吗?

    我正在用 C 制作一个 Windows 软件 我读过关于sql injection但我没有发现它适用于我的应用程序 SQL 注入在 winform 中有效吗 如果是的话如何预防 EDIT 我正在使用文本框来读取用户名和密码 通过使用 tex
  • 实现“计时器”的最佳方法是什么? [复制]

    这个问题在这里已经有答案了 实现计时器的最佳方法是什么 代码示例会很棒 对于这个问题 最佳 被定义为最可靠 失火次数最少 和最精确 如果我指定 15 秒的间隔 我希望每 15 秒调用一次目标方法 而不是每 10 20 秒调用一次 另一方面

随机推荐

  • 使用 Base64 和 JSON 上传大图像

    我正在使用此功能将图像上传到服务器JSON 为此 我首先将图像转换为NSData然后到NSString using Base64 当图像不是很大时 该方法工作正常 但当我尝试上传 2Mb 图像时 它会崩溃 问题是服务器没有收到我的图像 即使
  • 使用 Appcompat v7 的抽屉式导航 - ?android:attr 标签的问题

    我在我的项目中使用操作栏和导航抽屉 使用 appcompat v7 和 v4 我已经添加了 appcompat v7 和资源 以下是我的导航抽屉列表的文本视图 直接取自位于以下位置的 Android 示例应用程序 创建抽屉式导航 http
  • C#:通过反射检索和使用 IntPtr*

    我目前正在编写一些代码 这些代码反映了从调用本机 dll 中编组回来的结构 某些结构包含指向以 null 结尾的指针数组的 IntPtr 字段 这些领域需要特殊处理 当反映结构时 我可以识别这些字段 因为它们是由自定义属性标记的 以下说明了
  • ant-找不到符号@Test

    我正在尝试编译以下仅包含一个函数的类 公共类测试注释 Test public void testLogin System out println Testing Login 当我将文件作为 JUNIt 运行时 它可以工作 但是当我尝试从 b
  • 计算 a*a mod n 且不溢出

    I need to calculate a a mod n but a is fairly large resulting in overflow when I square it Doing a n a n n doesn t work
  • 树莓派蓝牙4.0连接

    我正在尝试使用 CoreBluetooth 蓝牙 4 0 通过 iPhone 连接到 Raspberry Pi 我已经发现了该设备并使用以下代码发出连接请求 if peripheral self foundPeripheral NSLog
  • Javascript ResizeObserver 意外触发

    Why the ResizeObserver类总是首先执行处理程序observe 尝试在 Chrome 开发工具上执行以下代码 new ResizeObserver gt console log resize detected observ
  • 从 asp.net 中的 dataSet 获取单个值

    我正在执行查询以从 tbl message 表获取 Title 和 RespondBY 我想在对转发器进行数据绑定之前解密标题 在进行数据绑定之前如何访问标题值 string MysqlStatement SELECT Title Resp
  • jQuery 显示/隐藏/切换有效,但没有保持应有的状态 - 它恢复到原始状态

    我尝试使用 jQuery 显示 隐藏常见问题解答 这个想法是列出所有问题 只有当用户想要查看答案时 他们才会单击问题 看起来像链接 然后答案就会变得可见 它有点有效 只不过一旦单击答案就会恢复到其原始状态 在这种情况下 这意味着当我单击问题
  • 对一列进行唯一约束,排除其他列中具有相同值的行

    我想向列添加唯一键value但我必须忽略列中具有相同值的行value and header id 例如 考虑这个表 id header id value 1 1 a 2 1 a 3 2 a 因此 第 1 行和第 2 行指向同一个对象 并且唯
  • 您可以在不同的 OSGi 包中拥有 JSF 自定义组件吗?

    有人同时使用过 OSGi 和 JSF 吗 我问这个问题是因为 JSF 使用类加载器魔法来查找自定义组件 来自教程 重点是我的 这个配置文件最终会 是 META INF faces config xml 中 代表此的 jar 文件 成分 JS
  • 如何在没有 Intent 的情况下以编程方式拨打电话

    我是 Android 新手 我想在不使用intent 我知道这段代码 Intent intent new Intent Intent ACTION CALL intent setData Uri parse tel bundle getSt
  • 如何将焦点设置到重复控件内的编辑框?

    我想将焦点设置为 将光标置于重复控件中的编辑框 最后一个 重复位于面板 panelRep 内 然后我在面板外面有一个按钮 这是几乎可以工作的按钮的客户端代码 焦点已设置 字段周围的蓝色边框 但光标未放置在字段中 用户仍必须单击该字段才能写入
  • C++ 中可重用的成员函数

    我正在使用这个成员函数来获取指向对象的指针 virtual Object Create return new Object 它是虚拟的 所以我可以获得指向派生对象的指针 现在我这样做 virtual Object Create return
  • 如何在 Google Cloud Platform (GCP) 中测试 Cloud Function?

    我一直在试图寻找这个问题的答案 但无法在任何地方找到它 在 Google Cloud Platform 控制台的 Cloud Functions 部分上 有一个部分标题为 测试 但我不知道应该在此处放置什么来测试该函数 即语法 I have
  • 设计和处理闪光灯

    我正在将 Devise 3 1 1 与 Rails 3 一起使用 并且我的布局中有以下闪存处理代码 我登录我的应用程序 Flash 说 Signed in successfully 然后注销 然后错误登录并闪烁显示 Signed out s
  • iPhone:如何编写减少倒数计时器的代码?

    我想使用显示倒计时器UILabel将从 5 开始并且每秒减少 1 like 5 4 3 2 1 最后当达到 0 时隐藏标签 我尝试使用它进行编码NSTimer scheduledTimerWithTimeInterval但惨败 请帮我 我只
  • 使用 Jest 模拟 Es6 类

    我正在尝试使用接收参数的构造函数来模拟 ES6 类 然后使用 Jest 模拟该类上的不同类函数以继续测试 问题是我找不到任何有关如何解决此问题的文档 我已经看过了这个帖子 https stackoverflow com questions
  • Java:为 Polynomial 类创建 toString 方法

    public String toString String mytoString if a equals 0 mytoString a toString x 2 if b equals 0 mytoString b toString x i
  • 我什么时候应该按值传递或返回结构体?

    在 C 中 结构体可以按值传递 返回 也可以按引用 通过指针 传递 返回 普遍的共识似乎是前者可以应用于小型结构 在大多数情况下不会受到惩罚 看在任何情况下 直接返回结构是一种好的做法吗 https stackoverflow com a