c - 访问 C 中的结构成员有多快?
问题描述
访问结构成员的过程是否比访问直接变量慢?如果我在多个地方使用了相同的结构成员,我应该在变量中声明它并将其保存在那里以节省多次访问同一成员的成本吗?我应该重复Struct.Member
Struct.Member
Struct.Member
还是应该将其保存在变量中int Member = Struct.Member
Member
Member
Member
?在什么时候我应该使用后者而不是前者?如果这些成员是位域怎么办?
解决方案
虽然访问结构成员与分配“直接”对象存在一些复杂性,但您的场景中更重要的区别是编译器可能能够更好地优化局部变量的使用而不是结构成员的使用。通过了。
这是因为结构通常是通过指针(即参数或来自另一个结构的指针)间接传递的。考虑这段代码:
struct S { int a; };
void baz(int);
void foo(struct S *s)
{
baz(s->a);
baz(s->a);
}
void bar(struct S *s)
{
int a = s->a;
baz(a);
baz(a);
}
在bar
中,编译器知道baz
不能改变a
,因为a
是一个永远不会占用地址的局部变量。因此,编译器可以s->a
从内存中加载一次并将其传递给baz
两次。
在foo
中,编译器无法知道baz
没有改变s->a
,因为baz
可能有某种访问方式,s->a
例如通过存储在外部对象中的地址。因此,它必须s->a
在第一次调用之前baz
以及在第一次调用和第二次调用之间再次加载。
使用启用了优化的 Apple Clang 11.0.0 进行测试证实了这一点;为例程生成的汇编代码foo
包含两个s->a
来自内存的加载,而代码bar
只包含一个。
尽管这经常发生在结构中,因为结构通常是通过地址传递的,但这并不是作为结构成员的固有结果。此代码中出现相同的问题:
void baz(int);
void foo(int *p)
{
baz(*p);
baz(*p);
}
void bar(int *p)
{
int a = *p;
baz(a);
baz(a);
}
即使没有调用子程序,它也可能发生;参数可以“干扰”其他参数。在下面的代码中,foo
必须重新加载z->a
但bar
不需要。即z
使用 限定const
,分配 tox
也可能会改变它:
struct S { int a; };
void foo(struct S *x, struct S *y, const struct S *z)
{
x->a = z->a;
y->a = z->a;
}
void bar(struct S *x, struct S *y, const struct S *z)
{
int a = z->a;
x->a = a;
y->a = a;
}
推荐阅读
- javascript - 由于(可能)错误的 bash 脚本导致一些奇怪的错误
- c# - 从 SMO TransferData 方法调用 CREATE INDEX 120 秒后“等待操作超时”
- python - 深度学习模型没有泛化
- c++ - std::cin 限制不能输入 LPCSTR
- java - javax.jcr.UnsupportedRepositoryOperationException:/testVersionable 处的节点不可版本化
- python - 在不迭代的情况下检测 Pandas DataFrame 列中的连续重复
- azure - 从数据工厂在 Azure VM 中执行 SSIS 包
- azure-cognitive-search - 如何将字符筛选器添加到 Azure 搜索中的 Microsoft 语言分析器?
- c# - C#向XML元素添加属性将命名空间附加到元素的末尾
- java - 如何将 JPA 实体与来自外部源的实体进行映射