编辑:如果你从根本上不同意这里的Fedora指南,请解释为什么这种方法会比传统循环更客观。据我所知,即使是CERT标准也没有对指针使用索引变量做任何说明。
我目前正在阅读Fedora Defensive Coding Guide,并建议如下:
始终跟踪您正在使用的阵列的大小。 通常情况下,当指针经过时,代码更明显是正确的 数组的最后一个元素,并计算剩余的数量 通过从该指针中减去当前位置的元素。该 替代方案,每次在位置时更新单独的变量 是先进的,通常不那么明确。
这意味着对于给定的数组
int numbers[] = {1, 2, 3, 4, 5};
我不应该使用经典
size_t length = 5;
for (size_t i = 0; i < length; ++i) {
printf("%d ", numbers[i]);
}
但改为:
int *end = numbers + 5;
for (int *start = numbers; start < end; ++start) {
printf("%d ", *start);
}
或者这个:
int *start = numbers;
int *end = numbers + 5;
while (start < end) {
printf("%d ", *start++);
}
答案 0 :(得分:2)
您对文本推荐内容的理解是正确的,您的实施也是如此。但是关于推荐的基础,我认为你将安全与正确混淆。
与使用索引相比,使用指针不是更安全。这个论点是,在推理代码时,使用指针时更容易确定逻辑正确。安全性是关于故障模式:如果代码不正确会发生什么(引用数组外的位置)。正确性更为基础:该算法可以证明其完成的工作要做。我们可能会说正确的代码不需要安全。
这项建议可能会受到几年前安德鲁科尼格博士在多布斯博士系列中的影响。 How C Makes It Hard To Check Array Bounds。柯尼希说,
除了在许多情况下速度更快之外,指针还有另一个优于数组的优势:指向数组元素的指针是一个足以唯一标识该元素的值。 [...]没有指针,我们需要三个参数来识别范围:数组和两个索引。通过使用指针,我们可以只使用两个参数。
在C中,引用数组外部的位置,无论是通过指针还是索引,同样不安全。编译器不会让你失望(没有使用标准的扩展)。 Koenig认为,空中球越少,你就能更好地掌握逻辑。
建筑越复杂,他就越明显。如果你想更好地说明差异,可以两种方式编写strcat(3)。使用索引,循环中有两个名称和两个索引 。可以将索引用于另一个具有名称的索引。使用指针,不可能。你只有两个指针。
答案 1 :(得分:1)
我的理解建议是否正确?
我的实施是否正确?
是的,所以看来。
当您拥有更复杂项目的数组时,有时会使用方法for(type_t start = &array; start != end; start++)
。这主要是风格问题。
当您因某些原因已经有可用的开始和结束指针时,有时会使用此样式。或者在你对大小不感兴趣的情况下,只是想反复比较数组的结尾。例如,假设您有一个带有开始指针和结束指针的环形缓冲区ADT,并希望迭代所有项目。
这种做循环的方式实际上就是为什么C显式允许指向数据的第1项超出范围的指针的原因,你可以在不调用未定义的行为的情况下设置一个指向一个项目的结束指针而不调用未定义的行为(因为该项目未被取消引用)。
(这与C ++中STL迭代器使用的方法完全相同,尽管C ++中有更多的基本原理,因为它有运算符重载。例如,C ++中的iterator++
不一定相邻地给出一个项目在下一个存储单元中分配。例如,迭代器可用于迭代链表ADT,其中++将转换为行后面的node->next
。)
然而,声称这种形式总是首选的只是主观的废话。特别是当你有一个整数数组并且知道大小时。您的第一个示例是C中循环中最易读的形式,因此始终首选。
在某些编译器/系统上,第一种形式也可以提供比第二种形式更快的代码。指针算术可能会在某些系统上提供较慢的代码。 (我认为第一种形式可能会在某些系统上提供更快的数据缓存访问,但我必须通过一些编译器专家来验证这种假设。)
最后2个中哪一个更安全?
两种形式都不比另一种形式更安全。否则主张是主观意见。声明“......通常不太明显正确”是无稽之谈。
选择哪种风格因具体情况而异。
总的来说,你链接的那些“Fedora”指南似乎包含许多有问题的代码,有问题的规则和公然的意见。似乎更像是某人想要展示各种C技巧而不是认真编写编码标准的尝试。总的来说,它闻起来像“Linux内核指南”,我不建议你阅读。