简体   繁体   English

在int数组上使用memcmp是否严格符合?

[英]Is using memcmp on array of int strictly conforming?

Is the following program a strictly conforming program in C? 以下程序是C中严格符合的程序吗? I am interested in c90 and c99 but c11 answers are also acceptable. 我对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;
}

In comments to my answer in a different question , Eric Postpischil insists that the program output will change depending on the platform, primarily due to the possibility of uninitialized padding bits. 对不同问题的答案的评论中 ,Eric Postpischil坚持认为程序输出将根据平台而改变,主要是由于未初始化填充位的可能性。 I thought the struct assignment would overwrite all bits in b to be the same as in a . 我认为结构分配会覆盖所有位b是一样a But, C99 does not seem to offer such a guarantee. 但是,C99似乎没有提供这样的保证。 From Section 6.5.16.1 p2: 从第6.5.16.1节第2节:

In simple assignment ( = ), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand. 简单赋值= )中,右操作数的值将转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。

What is meant by "converted" and "replaces" in the context of compound types? 在复合类型的背景下,“转换”和“替换”是什么意思?

Finally, consider the same program, except that the definitions of a and b are made global. 最后,考虑相同的程序,除了ab的定义是全局的。 Would that program be a strictly conforming program? 计划是否是严格遵守的计划?

Edit: Just wanted to summarize some of the discussion material here, and not add my own answer, since I don't really have one of my own creation. 编辑:只是想在这里总结一些讨论材料,而不是添加我自己的答案,因为我没有自己的创作。

  • The program is not strictly conforming. 该计划并不严格遵守。 Since the assignment is by value and not by representation, b.array may or may not contain bits set differently from a.array . 由于赋值是按值而不是表示,因此b.array可能包含也可能不包含与a.array不同的位。
  • a doesn't need to be converted since it is the same type as b , but the replacement is by value, and done member by member. a不需要转换,因为它与b类型相同,但是替换是按值,并按成员完成。
  • Even if the definitions in a and b are made global, post assignment, b.array may or may not contain bits set differently from a.array . 即使ab中的定义是全局的,post assignment, b.array可能包含也可能不包含与a.array不同的位。 (There was little discussion about the padding bytes in b , but the posted question was not about structure comparison. c99 lacks a mention of how padding is initialized in static storage, but c11 explicitly states it is zero initialized.) (关于b的填充字节几乎没有讨论,但是发布的问题不是关于结构比较.c99没有提到如何在静态存储中初始化填充,但是c11明确指出它是零初始化。)
  • On a side note, there is agreement that the memcmp is well defined if b was initialized with memcpy from a . 在一个侧面说明,有该协议memcmp如果被很好地定义b初始化所用memcpya

My thanks to all involved in the discussion. 我要感谢所有参与讨论的人。

In C99 §6.2.6 在C99§6.2.6中

§6.2.6.1 General §6.2.6.1总则

1 The representations of all types are unspecified except as stated in this subclause. 1除本条款规定外,所有类型的陈述均未指明。

[...] [...]

4 [..] Two values (other than NaNs) with the same object representation compare equal, but values that compare equal may have different object representations. 4 [..]具有相同对象表示的两个值(除NaN之外)比较相等,但比较相等的值可能具有不同的对象表示。

6 When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values. 6当值存储在结构或联合类型的对象中(包括在成员对象中)时,对应于任何填充字节的对象表示的字节采用未指定的值。 42) 42)

42) Thus, for example, structure assignment need not copy any padding bits. 42)因此,例如,结构分配不需要复制任何填充比特。

43) It is possible for objects x and y with the same effective type T to have the same value when they are accessed as objects of type T, but to have different values in other contexts. 43)具有相同有效类型T的对象x和y在作为类型T的对象访问时具有相同的值,但在其他上下文中具有不同的值。 In particular, if == is defined for type T, then x == y does not imply that memcmp(&x, &y, sizeof (T)) == 0. Furthermore, x == y does not necessarily imply that x and y have the same value; 特别是,如果为类型T定义了==,那么x == y并不意味着memcmp(&x,&y,sizeof(T))== 0.此外,x == y并不一定意味着x和y具有相同的价值; other operations on values of type T may distinguish between them. 对类型T的值的其他操作可以区分它们。

§6.2.6.2 Integer Types §6.2.6.2整数类型

[...] [...]

2 For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. 2对于有符号整数类型,对象表示的位应分为三组:值位,填充位和符号位。 There need not be any padding bits;[...] 不需要任何填充位; [...]

[...] [...]

5 The values of any padding bits are unspecified.[...] 5未指定任何填充位的值。[...]

In J.1 Unspecified Behavior 在J.1未指定的行为

  • The value of padding bytes when storing values in structures or unions (6.2.6.1). 在结构或联合中存储值时填充字节的值(6.2.6.1)。

[...] [...]

  • The values of any padding bits in integer representations (6.2.6.2). 整数表示中任何填充位的值(6.2.6.2)。

Therefore there may be bits in the representation of a and b that differ while not affecting the value. 因此, ab的表示中可能存在不同而不影响该值的位。 This is the same conclusion as the other answer, but I thought that these quotes from the standard would be good additional context. 这与其他答案的结论相同,但我认为标准中的这些引用将是良好的附加背景。


If you do a memcpy then the memcmp would always return 0 and the program would be strictly conforming. 如果你做一个memcpy那么memcmp将始终返回0并且程序将严格符合。 The memcpy duplicates the object representation of a into b . 所述memcpy复制的对象表示ab

My opinion is that it is strictly conforming. 我的意见是它严格遵守。 According to 4.5 that Eric Postpischil mentioned: 根据4.5,Eric Postpischil提到:

A strictly conforming program shall use only those features of the language and library specified in this International Standard. 严格符合的程序应仅使用本国际标准中规定的语言和库的特征。 It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior, and shall not exceed any minimum implementation limit. 它不应产生依赖于任何未指定,未定义或实现定义的行为的输出,并且不得超过任何最小实现限制。

The behavior in question is the behavior of memcmp , and this is well-defined, without any unspecified, undefined or implementation-defined aspects. 有问题的行为是memcmp的行为,这是明确定义的,没有任何未指定,未定义或实现定义的方面。 It works on the raw bits of the representation, without knowing anything about the values, padding bits or trap representations. 它适用于表示的原始位,不知道有关值,填充位或陷阱表示的任何信息。 Thus the result (but not the functionality ) of memcmp in this specific case depends on the implementation of the values stored within these bytes. 因此,在这种特定情况下, memcmp结果 (但不是功能 )取决于存储在这些字节中的值的实现。

Footnote 43) in 6.2.6.2: 6.2.6.2中的脚注43):

It is possible for objects x and y with the same effective type T to have the same value when they are accessed as objects of type T, but to have different values in other contexts. 具有相同有效类型T的对象x和y在作为类型T的对象访问时具有相同的值,但在其他上下文中具有不同的值。 In particular, if == is defined for type T, then x == y does not imply that memcmp(&x, &y, sizeof (T)) == 0. Furthermore, x == y does not necessarily imply that x and y have the same value; 特别是,如果为类型T定义了==,那么x == y并不意味着memcmp(&x,&y,sizeof(T))== 0.此外,x == y并不一定意味着x和y具有相同的价值; other operations on values of type T may distinguish between them. 对类型T的值的其他操作可以区分它们。

EDIT: 编辑:

Thinking it a bit further, I'm not so sure about the strictly conforming anymore because of this: 进一步思考,我不太确定严格符合,因为这样:

It shall not produce output dependent on any unspecified [...] 它不应产生依赖于任何未指明的[...]

Clearly the result of memcmp depends on the unspecified behavior of the representation, thereby fulfilling this clause, even though the behavior of memcmp itself is well defined. 很明显, memcmp的结果取决于表示的未指定行为,从而实现了该子句,即使memcmp本身的行为已被很好地定义。 The clause doesn't say anything about the depth of functionality until the output happens. 在输出发生之前,该子句没有说明功能的深度。

So it is not strictly conforming. 所以它并不严格符合。

EDIT 2: 编辑2:

I'm not so sure that it will become strictly conforming when memcpy is used to copy the struct. 当使用memcpy复制结构时,我不太确定它会变得严格符合。 According to Annex J, the unspecified behavior happens when a is initialized: 根据附件J,初始化a时会发生未指定的行为:

struct S a = { { 1, 2 } };

Even if we assume that the padding bits won't change and memcpy always returns 0, it still uses the padding bits to obtain its result. 即使我们假设填充位不会改变并且memcpy总是返回0,它仍然使用填充位来获得其结果。 And it relies on the assumption that they won't change, but there is no guarantee in the standard about this. 并且它依赖于它们不会改变的假设,但是标准中没有关于此的保证。

We should differentiate between paddings bytes in structs, used for alignment, and padding bits in specific native types like int . 我们应该区分结构中的填充字节,用于对齐,以及特定本机类型(如int填充位。 While we can safely assume that the padding bytes won't change, but only because there is no real reason for it, the same does not apply for the padding bits. 虽然我们可以安全地假设填充字节不会改变,但仅仅因为它没有真正的原因,同样不适用于填充位。 The standard mentions a parity flag as an example of a padding bit. 标准提到奇偶校验标志作为填充位的示例。 This may be a software function of the implementation, but it may as well be a hardware function. 这可以是实现的软件功能,但它也可以是硬件功能。 Thus there may be other hardware flags used for the padding bits, including one that changes on read accesses for whatever reason. 因此,可能存在用于填充比特的其他硬件标志,包括出于任何原因在读取访问上改变的标志。

We will have difficulties in finding such an exotic machine and implementation, but I see nothing that forbid this. 我们将难以找到这样一个奇特的机器和实现,但我没有看到任何禁止这一点。 Correct me if I'm wrong. 如果我错了纠正我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM