我有这样的数据结构:
struct foo {
int id;
int route;
int backup_route;
int current_route;
}
以及一个名为update()的函数,用于请求对其进行更改 .
update(42, dont_care, dont_care, new_route);
这真的很长,如果我在结构中添加一些东西,我必须在每次调用更新(...)时添加'dont_care' .
我正在考虑将结构传递给它,但事先用'dont_care'填充结构比在函数调用中拼写它更加繁琐 . 我可以在默认值为dont care的地方创建结构,并在我将其声明为局部变量后设置我关心的字段吗?
struct foo bar = { .id = 42, .current_route = new_route };
update(&bar);
将我希望表达的信息传递给更新功能的最优雅方法是什么?
我希望其他一切都默认为-1(“不关心”的密码)
10 回答
<stdarg.h>
允许您定义可变参数函数(它接受无限数量的参数,如printf()
) . 我将定义一个函数,它接受任意数量的参数对,一个指定要更新的属性,另一个指定值 . 使用enum
或字符串指定属性的名称 .虽然宏和/或函数(如已经建议的)将起作用(并且可能具有其他积极效果(即调试挂钩)),但它们比需要的更复杂 . 最简单且可能最优雅的解决方案是仅定义用于变量初始化的常量:
这段代码几乎没有理解间接的精神开销,并且非常清楚
bar
中您明确设置了哪些字段(安全地)忽略了那些未设置的字段 .您可以将您的秘密特殊值更改为0,并利用C的默认结构成员语义
然后将作为初始化程序中未指定的bar成员传递0 .
或者您可以创建一个将为您执行默认初始化的宏:
也许考虑使用预处理器宏定义:
如果你的(struct foo)实例是全局的,那么你当然不需要参数 . 但我假设您可能有多个实例 . 使用()块是适用于GCC的GNU-ism;这是一种将线条保持在一起的好方法(安全) . 如果以后需要在宏中添加更多内容,例如范围验证检查,则不必担心会破坏if / else语句等等 .
根据您指出的要求,我会这样做 . 像这样的情况是我开始大量使用python的原因之一;处理默认参数等变得比以往任何时候都简单得多 . (我猜这是一个python插件,对不起;-)
gobject使用的一种模式是可变参数函数,以及每个属性的枚举值 . 界面看起来像:
编写varargs函数很容易 - 请参阅http://www.eskimo.com/~scs/cclass/int/sx11b.html . 只需匹配键 - >值对并设置适当的结构属性 .
因为看起来你只需要
update()
函数的这个结构,所以根本不要使用它的结构,它只会模糊你的构造背后的意图 . 您可能应该重新考虑更改和更新这些字段的原因,并为此"little"更改定义单独的函数或宏 .例如
或者甚至更好地为每个变更案例编写一个函数 . 正如您已经注意到的那样,您不会同时更改每个属性,因此可以一次只更改一个属性 . 这不仅可以提高可读性,还可以帮助您处理不同的情况,例如:您不必检查所有“dont_care”,因为您知道只有当前路线发生了变化 .
怎么样的:
有:
和:
并相应地:
在C中,类似的模式有一个我不记得的名字 .
EDIT :它被称为Named Parameter Idiom .
我的结构生锈了,所以我可能在这里遗漏了几个关键词 . 但是为什么不从初始化默认值的全局结构开始,将其复制到本地变量,然后修改它?
初始化程序如:
然后当你想要使用它时:
你可以用X-Macro来解决这个问题
您可以将结构定义更改为:
然后,您将能够轻松定义一个灵活的函数,将所有字段设置为
dont_care
.在讨论here之后,还可以通过以下方式定义默认值:
这转化为:
并在hlovdal answer, with the advantage that here maintenance is easier, i.e. changing the number of struct members will automatically update foo_DONT_CARE 中使用它 . 注意the last "spurious" comma is acceptable .
当我必须解决this problem时,我首先学习了X-Macros的概念 .
对于添加到结构中的新字段,它非常灵活 . 如果您有不同的数据类型,您可以根据数据类型定义不同的
dont_care
值:从here,您可以从用于打印的函数中获取灵感第二个例子中的值 .如果您对所有
int
结构都没问题,那么您可以省略LIST_OF_foo_MEMBERS
中的数据类型,只需将结构定义的X函数更改为#define X(name) int name;
最优雅的方法是直接更新结构字段,而不必使用
update()
函数 - 但也许有充分的理由使用它在问题中没有遇到 .或者,您可以像Pukku建议的那样,为结构的每个字段创建单独的访问函数 .
否则,我能想到的最佳解决方案是将struct字段中的值“0”视为“不更新”标志 - 因此您只需创建一个函数来返回一个归零结构,然后使用它来更新 .
但是,如果0是结构中字段的有效值,则这可能不太可行 .