【发布时间】:2012-08-13 05:40:24
【问题描述】:
以下程序是 C 语言中的严格符合程序吗?我对 c90 和 c99 感兴趣,但 c11 的答案也可以接受。
#include <stdio.h>
#include <string.h>
struct S { int array[2]; };
int main () {
struct S a = { { 1, 2 } };
struct S b;
b = a;
if (memcmp(b.array, a.array, sizeof(b.array)) == 0) {
puts("ok");
}
return 0;
}
在comments to my answer in a different question 中,Eric Postpischil 坚持认为程序输出会因平台而异,这主要是由于可能存在未初始化的填充位。我认为结构赋值会覆盖b 中的所有位,使其与a 中的相同。但是,C99 似乎没有提供这样的保证。来自第 6.5.16.1 p2 节:
在简单赋值(
=)中,右操作数的值被转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。
复合类型上下文中的“转换”和“替换”是什么意思?
最后,考虑同一个程序,除了 a 和 b 的定义是全局的。 那个程序会是一个严格遵从的程序吗?
编辑:只是想在这里总结一些讨论材料,而不是添加我自己的答案,因为我真的没有自己的创作。
- 程序不严格符合。由于赋值是按值而不是按表示,
b.array可能包含也可能不包含与a.array不同的位设置。 -
a不需要转换,因为它和b是同一类型,但是替换是按值,逐个成员完成。 - 即使
a和b中的定义是全局的,在分配后,b.array可能包含也可能不包含与a.array不同的位设置。 (b中几乎没有关于填充字节的讨论,但发布的问题与结构比较无关。c99 没有提及如何在静态存储中初始化填充,但 c11 明确声明它是零初始化的。) - 附带说明,如果
b是用来自a的memcpy初始化的,那么memcmp是明确定义的。
感谢所有参与讨论的人。
【问题讨论】:
-
与填充无关,也不适用于问题中使用的 1 和 2 值,但仍然本着它的精神,我没有发现任何东西阻止考虑 -0 的符号和幅度或补码实现作为一种冗余方式来表示 0 以在分配时对其进行规范化。
-
你在问题中的例子仍然不是一个好例子。您不是在比较
struct,因为这似乎是您的意图,而只是数组。因此,在您在此处给出的示例中,问题仍然只是int是否具有填充位,或者例如所谓的负零。这些事情不会发生在现代架构上。您真的必须考虑一个具有实际填充字节(而不是填充位)的真实结构,以便问题变得相关。 -
@JensGustedt:这个问题具体是关于
memcmp的数组int,struct用于对b持有的数组进行赋值。 -
@user315052,对于数组,
memcpy就可以了。memcpy和memcmp在字节基础上工作,这些字节被视为unsigned char。 ` unsigned char` 是唯一保证没有填充位并且所有表示都有不同值的数据类型。 -
Eric 是 SO 上为数不多的人之一,在涉及 C 标准语言律师的情况下,您几乎可以简单地从表面上接受他的意见。
标签: c language-lawyer