Ist es legal, memset(…, 0, …) auf einem Array von Doubles zu verwenden?

Lesezeit: 7 Minuten

Benutzeravatar von Andrei
Andrej

Ist es legal, den Speicher eines Arrays von Doubles (mit memset(…, 0, …)) oder eine Struktur, die Doubles enthält?

Die Frage impliziert zweierlei:

  1. Aus Sicht der C-Norm: Ist dieses undefinierte Verhalten nicht? (Auf einer bestimmten Plattform, nehme ich an, kann dies kein undefiniertes Verhalten sein, da es nur von der In-Memory-Darstellung von Gleitkommazahlen abhängt – das ist alles.)

  2. Aus praktischer Sicht: Ist es auf der Intel-Plattform in Ordnung? (Egal was der Standard sagt.)

Benutzeravatar von Matteo Italia
Matteo Italien

Der C99-Standard Anhang F sagt:

Dieser Anhang spezifiziert die C-Sprachunterstützung für die IEC 60559 Gleitkommastandard. Der Gleitkommastandard IEC 60559 ist speziell binäre Gleitkommaarithmetik für Mikroprozessorsysteme, zweite Ausgabe (IEC 60559:1989)zuvor bezeichnet
IEC559:1989 und wie IEEE-Standard für binäre Gleitkommaarithmetik (ANSI/IEEE 754−1985). IEEE-Standard für wurzelunabhängige Gleitkommaarithmetik (ANSI/IEEE 854−1987) verallgemeinert den binären Standard, um Abhängigkeiten von Basis und Wortlänge zu entfernen. IEC 60559 bezieht sich im Allgemeinen auf den Gleitkommastandard, wie im IEC 60559-Betrieb, im IEC 60559-Format usw. Eine Implementierung, die definiert __STDC_IEC_559__ müssen den Spezifikationen in diesem Anhang entsprechen. Wo eine Bindung zwischen der C-Sprache und IEC 60559 angegeben ist, wird das von IEC 60559 spezifizierte Verhalten durch Verweis übernommen, sofern nicht anders angegeben.

Und gleich danach:

Die Floating-Typen von C stimmen wie folgt mit den IEC 60559-Formaten überein:

  • Das float Typ stimmt mit dem Einzelformat nach IEC 60559 überein.
  • Das double type stimmt mit dem Doppelformat nach IEC 60559 überein.

Da IEC 60559 im Grunde genommen IEEE 754-1985 ist und dies angibt, dass 8 Nullbytes 0,0 bedeuten (wie @David Heffernan sagte), bedeutet dies das wenn du findest __STDC_IEC_559__ definiert, können Sie sicher eine 0.0-Initialisierung mit durchführen memset.

  • Es ist also IEEE754, es sei denn, die Compiler-Dokumentation gibt ausdrücklich etwas anderes an?

    – Martin York

    7. Januar 2011 um 23:27 Uhr

  • Eigentlich, so wie ich es verstanden habe, ist es umgekehrt: Es kann alles sein, aber wenn man es definiert findet __STDC_IEC_559__ Sie können sicher sein, dass es sich um IEC 60559 alias IEEE 754 handelt.

    – Matteo Italien

    7. Januar 2011 um 23:29 Uhr


Wenn Sie über IEEE754 sprechen, definiert der Standard +0,0 mit doppelter Genauigkeit als 8 Null-Bytes. Wenn Sie wissen, dass Sie von IEEE754-Gleitkomma unterstützt werden, ist dies wohldefiniert.

Was Intel betrifft, fällt mir kein Compiler ein, der IEEE754 auf Intel x86/x64 nicht verwendet.

  • Was ist mit all den mobilen Geräten, für die Menschen entwickeln? Verwenden sie alle IEEE754?

    – Martin York

    7. Januar 2011 um 23:27 Uhr

  • Aus praktischer Sicht glaube ich jedoch nicht, dass jemand, der ein Fließkommaformat entwirft, es jemals so machen wird, dass die Einstellung a double auf Null wird es problematisch werden. :)

    – Matteo Italien

    7. Januar 2011 um 23:47 Uhr


Benutzeravatar von Matthew Slattery
Matthew Slattery

David Heffernan hat Teil (2) Ihrer Frage gut beantwortet. Für Teil (1):

Das C99 standard übernimmt keine Garantien für die Darstellung von Fließkommawerten im allgemeinen Fall. §6.2.6.1 sagt:

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

… und dieser Unterabschnitt erwähnt Gleitkommazahlen nicht weiter.

Du sagtest:

(auf einer festen Plattform, wie kann diese UB … es kommt nur auf die schwebende Darstellung an, das ist alles …)

In der Tat – es gibt einen Unterschied zwischen “nicht definiert Verhalten”, “nicht spezifiziert Verhalten” und “implementierungsdefiniert Verhalten”:

  • nicht definiert Verhalten” bedeutet, dass alles passieren könnte (einschließlich eines Laufzeitabsturzes);
  • nicht spezifiziert Verhalten” bedeutet, dass es dem Compiler freisteht, etwas Sinnvolles auf beliebige Weise zu implementieren, aber es besteht keine Notwendigkeit, dass die Auswahl der Implementierung dokumentiert wird;
  • implementierungsdefiniert Verhalten” bedeutet, dass der Compiler frei ist, etwas Sinnvolles auf beliebige Weise zu implementieren, und diese Wahl dokumentieren soll (zum Beispiel siehe hier für die Implementierungsoptionen, die in der neuesten Version von dokumentiert sind GCC);

und so, als Fließkommadarstellung ist nicht spezifiziert Verhalten, kann es auf undokumentierte Weise von Plattform zu Plattform variieren (wobei “Plattform” hier “die Kombination aus Hardware und Compiler” und nicht nur “Hardware” bedeutet).

(Ich bin mir nicht sicher, wie nützlich die Garantie ist, dass a double so dargestellt wird, dass alle Bits Null sind +0.0 wenn __STDC_IEC_559__ definiert ist, wie in der Antwort von Matteo Italia beschrieben, tatsächlich in der Praxis ist. Zum Beispiel, GCC definiert dies nieobwohl es auf vielen Hardwareplattformen IEEE 754 / IEC 60559 verwendet.)

  • Ich würde einfach IEEE 754 annehmen, da es sonst genauso gut zu Gleitkommaverhalten kommen könnte rand().

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. Januar 2011 um 23:02 Uhr

  • Verwenden alle Handheld-Geräte IEEE754 als Fließkommadarstellung? Desktop mag relativ Standard sein, aber der Markt für mobile Geräte ist etwas zersplitterter.

    – Martin York

    7. Januar 2011 um 23:32 Uhr

Auch wenn es unwahrscheinlich ist, dass Sie auf eine Maschine stoßen, bei der dies Probleme hat, können Sie dies auch relativ leicht vermeiden, wenn Sie wirklich davon sprechen Arrays wie Sie im Titel der Frage angeben, und wenn diese Arrays zur Kompilierzeit eine bekannte Länge haben (d.h nicht VLA), dann ist es wahrscheinlich noch bequemer, sie einfach zu initialisieren:

double A[133] = { 0 };

sollte immer funktionieren. Wenn Sie ein solches Array später erneut auf Null setzen müssen und Ihr Compiler mit modernem C (C99) kompatibel ist, können Sie dies mit einem zusammengesetzten Literal tun

memcpy(A, (double const[133]){ 0 }, 133*sizeof(double));

Auf jedem modernen Compiler sollte dies so effizient sein wie memsethat aber den Vorteil, dass man sich nicht auf eine bestimmte Codierung von verlässt double.

Benutzeravatar von Andrei Sfrent
Andrej Sfrent

Wie Matteo Italia sagt, ist das laut Standard legal, aber ich würde es nicht verwenden. Etwas wie

double *p = V, *last = V + N;  // N is count
while (p != last) *(p++) = 0;

ist mindestens doppelt so schnell.

  • Ich bezweifle ernsthaft, dass es schneller ist, und würde erwarten, dass es viel langsamer ist. memset ist in der Regel aus gutem Grund die am besten optimierte Funktion in jeder C-Bibliotheksimplementierung.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. Januar 2011 um 23:03 Uhr

  • Es ist vielleicht nicht schneller, aber es ist sicherer und der Geschwindigkeitsunterschied wird in den meisten Situationen vernachlässigbar sein.

    – Martin York

    7. Januar 2011 um 23:30 Uhr

  • Ich habe den Code vor dem Posten getestet (für N = 10 ^ 7, auf einem Linux-Rechner) und schien schneller zu sein als memset(V, 0, N * sizeof(double)).

    – Andrej Sfrent

    7. Januar 2011 um 23:44 Uhr

  • Ein Memset wird oft direkt vom Compiler inliniert und auch in der VPU implementiert, was bedeutet, dass es in jeder Iteration 128 Bit löschen kann. Wenn Ihre Schleife schneller ist, verwenden Sie wahrscheinlich einen beschissenen Compiler oder haben diese Optimierungen ausgeschaltet.

    – eine Masse

    8. Januar 2011 um 8:13 Uhr


  • Das ist falsch. Ohne Optimierungen ist die memset wird schneller sein. Mit Optimierungen sollte jeder moderne Compiler denselben Code generieren.

    – Eichel

    8. Mai 2019 um 9:42 Uhr

Benutzeravatar von ib
ib.

Die Verwendung ist „legal“. memset. Die Frage ist, ob es wo ein Bitmuster erzeugt array[x] == 0.0 ist wahr. Während der grundlegende C-Standard dies nicht erfordert, wäre ich daran interessiert, Beispiele zu hören, wo dies nicht der Fall ist!

Es scheint, dass die Einstellung auf Null über memset entspricht der Zuweisung von 0.0 auf IBM-AIX, HP-UX (PARISC), HP-UX (IA-64), Linux (IA-64, glaube ich).

Hier ist ein trivialer Testcode:

double dFloat1 = 0.0;
double dFloat2 = 111111.1111111;

memset(&dFloat2, 0, sizeof(dFloat2));

if (dFloat1 == dFloat2) {
    fprintf(stdout, "memset appears to be equivalent to = 0.0\n");
} else {
    fprintf(stdout, "memset is NOT equivalent to = 0.0\n");
}

  • Ich bezweifle ernsthaft, dass es schneller ist, und würde erwarten, dass es viel langsamer ist. memset ist in der Regel aus gutem Grund die am besten optimierte Funktion in jeder C-Bibliotheksimplementierung.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. Januar 2011 um 23:03 Uhr

  • Es ist vielleicht nicht schneller, aber es ist sicherer und der Geschwindigkeitsunterschied wird in den meisten Situationen vernachlässigbar sein.

    – Martin York

    7. Januar 2011 um 23:30 Uhr

  • Ich habe den Code vor dem Posten getestet (für N = 10 ^ 7, auf einem Linux-Rechner) und schien schneller zu sein als memset(V, 0, N * sizeof(double)).

    – Andrej Sfrent

    7. Januar 2011 um 23:44 Uhr

  • Ein Memset wird oft direkt vom Compiler inliniert und auch in der VPU implementiert, was bedeutet, dass es in jeder Iteration 128 Bit löschen kann. Wenn Ihre Schleife schneller ist, verwenden Sie wahrscheinlich einen beschissenen Compiler oder haben diese Optimierungen ausgeschaltet.

    – eine Masse

    8. Januar 2011 um 8:13 Uhr


  • Das ist falsch. Ohne Optimierungen ist die memset wird schneller sein. Mit Optimierungen sollte jeder moderne Compiler denselben Code generieren.

    – Eichel

    8. Mai 2019 um 9:42 Uhr

Benutzeravatar von user541686
Benutzer541686

Nun, ich denke, das Nullsetzen ist “legal” (schließlich wird ein normaler Puffer genullt), aber ich habe keine Ahnung, ob der Standard Sie etwas über den resultierenden logischen Wert annehmen lässt. Meine Vermutung wäre, dass der C-Standard es als undefiniert lässt.

1398710cookie-checkIst es legal, memset(…, 0, …) auf einem Array von Doubles zu verwenden?

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

Privacy policy