Ist die Verwendung von memcmp auf einem Array von int streng konform?

Lesezeit: 9 Minuten

Benutzer-Avatar
jxh

Ist das folgende Programm ein streng konformes Programm in C? Ich interessiere mich für c90 und c99, aber c11-Antworten sind auch akzeptabel.

#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 Kommentaren zu meiner Antwort in einer anderen Frage besteht Eric Postpischil darauf, dass sich die Programmausgabe je nach Plattform ändern wird, hauptsächlich aufgrund der Möglichkeit nicht initialisierter Füllbits. Ich dachte, die Strukturzuweisung würde alle Bits überschreiben b gleich sein wie in a. Aber C99 scheint eine solche Garantie nicht zu bieten. Aus Abschnitt 6.5.16.1 p2:

Im einfache Aufgabe (=), wird der Wert des rechten Operanden in den Typ des Zuweisungsausdrucks konvertiert und ersetzt den Wert, der in dem durch den linken Operanden bezeichneten Objekt gespeichert ist.

Was ist mit „konvertiert“ und „ersetzen“ im Zusammenhang mit zusammengesetzten Typen gemeint?

Betrachten Sie schließlich dasselbe Programm, außer dass die Definitionen von a und b werden global gemacht. Möchten das Programm ein streng konformes Programm sein?

Bearbeiten: Ich wollte nur einen Teil des Diskussionsmaterials hier zusammenfassen und keine eigene Antwort hinzufügen, da ich nicht wirklich eine eigene Kreation habe.

  • Das Programm ist nicht streng konform. Da die Zuordnung nach Wert und nicht nach Repräsentation erfolgt, b.array kann Bits enthalten oder nicht, die anders gesetzt sind als a.array.
  • a muss nicht konvertiert werden, da es derselbe Typ ist wie baber die Ersetzung erfolgt nach Wert und erfolgt Mitglied für Mitglied.
  • Auch wenn die Definitionen in a und b werden global gemacht, Postzuordnung, b.array kann Bits enthalten oder nicht, die anders gesetzt sind als a.array. (Es gab wenig Diskussion über die Füllbytes in b, aber in der geposteten Frage ging es nicht um den Strukturvergleich. In c99 wird nicht erwähnt, wie Padding im statischen Speicher initialisiert wird, aber c11 gibt ausdrücklich an, dass es mit Null initialisiert ist.)
  • Nebenbei bemerkt besteht Einigkeit darüber, dass die memcmp ist wohldefiniert wenn b wurde mit initialisiert memcpy aus a.

Mein Dank gilt allen an der Diskussion Beteiligten.

  • Nicht im Zusammenhang mit dem Auffüllen und nicht anwendbar auf die in der Frage verwendeten Werte 1 und 2, aber immer noch in seinem Sinne, habe ich nichts gefunden, was eine Implementierung von Vorzeichen und Größe oder Einerkomplement verhindert, die -0 als eine redundante Möglichkeit zur Darstellung von 0 bis betrachtet Normalisieren Sie es bei der Zuweisung.

    – Ein Programmierer

    16. August 2012 um 20:31 Uhr

  • Ihr Beispiel in der Frage ist immer noch kein gutes. Du vergleichst das nicht struct wie es scheint Ihre Absicht, aber nur die Arrays. In dem Beispiel, das Sie hier geben, ist es also immer noch nur die Frage ob int hat Füllbits oder zB sogenannte negative Nullen. Diese Dinge passieren nicht auf modernen Architekturen. Sie müssten sich wirklich eine echte Struktur mit echten Füllbytes (und nicht Füllbits) überlegen, damit das Problem relevant wird.

    – Jens Gustedt

    16. August 2012 um 22:12 Uhr

  • @JensGustedt: Die Frage bezieht sich speziell auf memcmp mit Array von intund die struct wird verwendet, um die Zuweisung in das von gehaltene Array zu bewirken b.

    – jxh

    16. August 2012 um 22:15 Uhr


  • @ user315052, für Arrays wäre es in Ordnung memcpy. memcpy und memcmp arbeiten auf einer Byte-Basis, diese Bytes als gesehen unsigned char. “unsigned char” ist der einzige Datentyp, der garantiert kein Füllbit hat und bei dem alle Darstellungen unterschiedliche Werte haben.

    – Jens Gustedt

    16. August 2012 um 22:19 Uhr

  • Eric ist einer der wenigen Leute bei SO, dessen Meinung man ziemlich einfach für bare Münze nehmen kann, wenn es um Rechtsanwälte in C-Standardsprache geht.

    – Stefan Kanon

    16. August 2012 um 22:20 Uhr

Benutzer-Avatar
Geoff Reedy

In C99 §6.2.6

§6.2.6.1 Allgemeines

1 Die Darstellungen aller Arten sind nicht spezifiziert, außer wie in diesem Unterabschnitt angegeben.

[…]

4 [..] Zwei Werte (außer NaNs) mit derselben Objektdarstellung sind im Vergleich gleich, aber Werte, die im Vergleich gleich sind, können unterschiedliche Objektdarstellungen haben.

6 Wenn ein Wert in einem Objekt vom Typ Struktur oder Union gespeichert wird, einschließlich in einem Mitgliedsobjekt, nehmen die Bytes der Objektdarstellung, die Füllbytes entsprechen, unspezifizierte Werte an.42)

42) So braucht zB die Strukturzuweisung keine Füllbits zu kopieren.

43) Es ist möglich, dass Objekte x und y mit demselben effektiven Typ T denselben Wert haben, wenn auf sie als Objekte des Typs T zugegriffen wird, aber in anderen Kontexten unterschiedliche Werte haben. Insbesondere wenn == für den Typ T definiert ist, impliziert x == y nicht, dass memcmp(&x, &y, sizeof (T)) == 0. Außerdem impliziert x == y nicht unbedingt, dass x und y denselben Wert haben; andere Operationen mit Werten vom Typ T können zwischen ihnen unterscheiden.

§6.2.6.2 Integer-Typen

[…]

2 Für vorzeichenbehaftete Integer-Typen sind die Bits der Objektdarstellung in drei Gruppen zu unterteilen: Wertbits, Füllbits und das Vorzeichenbit. Es müssen keine Füllbits vorhanden sein;[…]

[…]

5 Die Werte aller Füllbits sind nicht angegeben.[…]

In J.1 Nicht spezifiziertes Verhalten

  • Der Wert von Füllbytes beim Speichern von Werten in Strukturen oder Vereinigungen (6.2.6.1).

[…]

  • Die Werte aller Füllbits in ganzzahligen Darstellungen (6.2.6.2).

Daher können Bits in der Darstellung von enthalten sein a und b die sich unterscheiden, ohne den Wert zu beeinflussen. Dies ist die gleiche Schlussfolgerung wie die andere Antwort, aber ich dachte, dass diese Zitate aus dem Standard einen guten zusätzlichen Kontext darstellen würden.


Wenn Sie eine memcpy dann ist die memcmp würde immer 0 zurückgeben und das Programm wäre streng konform. Das memcpy dupliziert die Objektdarstellung von a hinein b.

  • Vielen Dank! Es sollte also sicher sein, a zu tun memcmp nach einer memcpy obwohl, da memcpy kopiert die gleichen Bits, richtig?

    – jxh

    16. August 2012 um 21:18 Uhr

  • @ user315052 ja, das wäre konform; siehe Details in der Antwort

    – Geoff Reedy

    16. August 2012 um 22:11 Uhr

Benutzer-Avatar
Sicher

Meine Meinung ist, dass es streng konform ist. Laut 4.5, den Eric Postpischil erwähnte:

Ein streng konformes Programm darf nur die Merkmale der Sprache und Bibliothek verwenden, die in dieser Internationalen Norm spezifiziert sind. Es darf keine Ausgabe abhängig von unspezifiziertem, undefiniertem oder implementierungsdefiniertem Verhalten erzeugen und darf keine minimale Implementierungsgrenze überschreiten.

Das fragliche Verhalten ist das Verhalten von memcmp, und dies ist wohldefiniert, ohne unspezifizierte, undefinierte oder implementierungsdefinierte Aspekte. Es arbeitet mit den rohen Bits der Darstellung, ohne etwas über die Werte, Füllbits oder Trap-Darstellungen zu wissen. Und so kam es dass der Ergebnis (aber nicht die Funktionalität) von memcmp hängt in diesem speziellen Fall von der Implementierung der in diesen Bytes gespeicherten Werte ab.

Fußnote 43) in 6.2.6.2:

Es ist möglich, dass Objekte x und y mit demselben effektiven Typ T denselben Wert haben, wenn auf sie als Objekte des Typs T zugegriffen wird, aber in anderen Kontexten unterschiedliche Werte haben. Insbesondere wenn == für den Typ T definiert ist, impliziert x == y nicht, dass memcmp(&x, &y, sizeof (T)) == 0. Außerdem impliziert x == y nicht unbedingt, dass x und y denselben Wert haben; andere Operationen mit Werten vom Typ T können zwischen ihnen unterscheiden.

BEARBEITEN:

Wenn ich etwas weiter denke, bin ich mir wegen der strikten Einhaltung nicht mehr so ​​sicher:

Es soll keine abhängige Ausgabe produzieren irgendein nicht spezifiziert […]

Eindeutig das Ergebnis von memcmp hängt von dem nicht spezifizierten Verhalten der Darstellung ab, wodurch diese Klausel erfüllt wird, obwohl das Verhalten von memcmp selbst ist gut definiert. Die Klausel sagt nichts über die Tiefe der Funktionalität aus, bis die Ausgabe erfolgt.

So ist es nicht streng konform.

BEARBEITEN 2:

Ich bin mir nicht so sicher, ob es wann streng konform wird memcpy wird verwendet, um die Struktur zu kopieren. Gemäß Anhang J tritt das nicht spezifizierte Verhalten auf, wenn a wird initialisiert:

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

Auch wenn wir davon ausgehen, dass sich die Füllbits nicht ändern und memcpy immer 0 zurückgibt, verwendet es immer noch die Füllbits, um sein Ergebnis zu erhalten. Und es beruht auf der Annahme, dass sie sich nicht ändern werden, aber dafür gibt es im Standard keine Garantie.

Wir sollten zwischen Füllbytes in Strukturen, die für die Ausrichtung verwendet werden, und Füllbits in bestimmten nativen Typen wie int. Während wir davon ausgehen können, dass sich die Füllbytes nicht ändern, aber nur weil es keinen wirklichen Grund dafür gibt, gilt das Gleiche nicht für die Füllbits. Als Beispiel für ein Füllbit nennt der Standard ein Parity-Flag. Dies kann eine Softwarefunktion der Implementierung sein, aber es kann auch eine Hardwarefunktion sein. Daher können andere Hardware-Flags für die Füllbits verwendet werden, einschließlich eines, das sich aus irgendeinem Grund bei Lesezugriffen ändert.

Wir werden Schwierigkeiten haben, eine so exotische Maschine und Implementierung zu finden, aber ich sehe nichts, was dies verbietet. Korrigieren Sie mich, wenn ich falsch liege.

  • Das Programm kann “ok” oder nichts produzieren. Wenn das Programm auf einer Plattform “ok” produziert, aber nicht auf einer anderen, würde das nicht bedeuten, dass die Ausgabe von etwas abhängt, das nicht genau definiert ist?

    – jxh

    16. August 2012 um 21:46 Uhr

  • @jxh: Wenn die von einem Programm erzeugte Zeichenfolge nicht von einer Plattform zur anderen variieren darf, wäre es für ein streng konformes Programm ziemlich schwierig, es zu verwenden rand(). Eine hilfreichere Definition von Konformität wäre, dass ein Programm muss seine Anforderungen erfüllen auf jeder standardkonformen Plattform; Wenn die Anforderungen des obigen Programms besagen, dass es entweder “ok” oder nichts ausgeben muss, aber nicht die Zeichenfolge “Fred” ausgeben darf, wäre das obige Programm nach vernünftigem Lesen des Standards streng konform [though it might exceed minimalist implementation limits].

    – Superkatze

    29. Juli 2015 um 17:37 Uhr

  • @supercat: Mein Kommentar beschränkte sich auf das Beispielprogramm, nicht auf eine allgemeine Spezifikation des Programmverhaltens.

    – jxh

    29. Juli 2015 um 18:08 Uhr

  • @jxh: Meins auch. Wenn Ihr Programm auf einer standardkonformen Plattform ein undefiniertes Verhalten hervorrufen könnte, könnte eine standardkonforme Plattform Code generieren, der “Fred” ausgibt. Selbst wenn die einzige Anforderung für Ihr Programm darin bestand, “Fred” nicht auszugeben, könnte es standardkonforme Plattformen geben, auf denen Ihr Programm diese Anforderung verletzen würde, wenn Ihr Programm Undefiniertes Verhalten aufruft. Da es UB jedoch nicht aufruft, müssen alle standardkonformen Implementierungen Code generieren, der die Anforderung erfüllt, “Fred” nicht auszugeben.

    – Superkatze

    29. Juli 2015 um 18:57 Uhr


  • @supercat: Sie haben den Begriff der Verwendung eingeführt rand(), was nicht unbedingt das gleiche Programm erfordern würde, um die gleiche Ausgabe zu erzeugen. Ich habe in meinem Kommentar erklärt, dass mein Beispielprogramm, wenn es streng konform ist, die gleiche Ausgabe für alle konformen Compiler erzeugen sollte. Die ursprüngliche Version dieser Antwort hatte etwas dahingehend gesagt, dass das Programm konform sei, selbst wenn es auf verschiedenen Plattformen unterschiedliche Ausgaben erzeugen könnte.

    – jxh

    29. Juli 2015 um 20:47 Uhr


1355250cookie-checkIst die Verwendung von memcmp auf einem Array von int streng konform?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy