Was können Menschen machen, die aus den Schränken qualifier?
-
19-09-2019 - |
Frage
Wenn ich die C99 restrict
Stichwort Recht, qualifying einen Zeiger mit es ist ein Versprechen, dass die Daten, die es verweist, nicht geändert werden hinter den compiler zurück durch aliasing.
Durch Kontrast, die so verstehe ich das const
qualifier ist als die vom compiler erzwungen Dokumentation, die ein bestimmtes Objekt wird nicht geändert werden, hinter dem Rücken eines Menschen code schreiben.Der compiler könnte eine Andeutung als Nebenwirkung, sondern als ein Programmierer, der ich nicht wirklich.
In ähnlicher Weise wäre es angemessen zu erwägen, eines restrict
qualifier in einer Funktion, die als Prototyp einer Anforderung, dass der Benutzer garantiert, die exklusiven Zugang ("Vermeidung von aliasing" oder vielleicht etwas stärkeres) für die Dauer des Gesprächs?Sollte es verwendet werden als die "Dokumentation"?
Außerdem gibt es etwas zu verstehen in der Tatsache, dass restrict
qualifiziert sich ein Zeiger, anstatt die Daten, die Sie Punkte (wie const
es tut) ?
EDIT:Ich hatte ursprünglich angenommen, dass restrict
könnte auch Auswirkungen mit Gewinde-code, aber dies scheint falsch, so Entferne ich Verweise auf threads von der Frage zu vermeiden verwirrend Leser.
Lösung
Die beste ‚Intuition‘ über das haben, beschränkt Schlüsselwort ist, dass es eine Garantie (vom Programmierer an die Compiler), dass für die gesamte Lebensdauer des Zeigers über diesen Zeiger zugegriffen Speicher wird nur über diesen Zeiger zugegriffen werden und nicht über einen anderen Zeiger oder eine Referenz oder globale Adresse. So ist es wichtig, dass sie auf einem Zeiger als eine Eigenschaft von sowohl den Zeiger und dem Speicher, die beide zusammen zu binden, bis der Zeiger den Gültigkeitsbereich verlassen.
Andere Tipps
Chris Dodd hat die korrekte Beschreibung des Keywords. In bestimmten Plattformen kann es aus Performance-Gründen sehr wichtig sein, weil es der Compiler wissen lässt, dass, sobald es Daten über diesen Zeiger auf ein Register geladen ist, es nicht wieder tun muss. Ohne diese Garantie muss der Compiler die Daten über einen Zeiger jedes Mal ein anderer möglicherweise Aliasing-Zeiger wird geschrieben durch, lädt die eine ernsthafte Pipeline-Blockierung verursachen kann ein load-hit-store .
const
und restrict
sind unterschiedliche Konzepte, und es ist nicht der Fall, dass const
restrict
impliziert. Alle const
sagt, ist, dass Sie nicht durch diesen Zeiger im Rahmen dieser Funktion schreiben. Ein const
Zeiger kann noch aliased werden. Zum Beispiel betrachten:
int foo( const int *a, int * b )
{
*b *= 2;
return *a + *b; // induces LHS: *a must be read back immediately
// after write has cleared the store queue
}
Sie können zwar nicht direkt schreiben können in dieser Funktion a
, wäre es vollkommen legal für Sie foo nennen wie:
int x = 3;
foo( &x, &x ); // returns 12
restrict
ist eine andere Garantie:. Ein Versprechen, das in allen Anrufen a != b
foo()
Ich habe geschrieben über die Das meiste, was Sie wissen ist falsch! const tut nicht Garantie, dass etwas nicht ändern, hinter den compiler zurück.Alle es tut, ist zu stoppen Sie vom schreiben auf die spot.Etwas anderes könnte noch in der Lage sein zu schreiben Sie zu diesem Speicherort, obwohl, so dass der compiler nicht davon ausgehen, es ist konstant. Wie andere gesagt haben, ist das einschränken der Beiname ist über aliasing.In der Tat, während der ersten Runde der C-Standardisierung war es, einen Vorschlag für eine "noalias" keyword.Leider wurde der Vorschlag ziemlich schlecht geschrieben-es aufgefordert, die einzige Zeit, die Dennis Ritchie geriet während dieser Prozess, wenn er einen Brief schrieb, der sagte etwas zu dem Effekt, dass "noalias gehen muss.Diese ist nicht offen für Verhandlungen." Unnötig zu sagen, 'noalias' nicht werden, Teil C.Wenn es Zeit kam, um erneut zu versuchen, der Vorschlag wurde genug geschrieben, besser beschränken, wurde in der Norm -- und obwohl noalias hätte wohl einen aussagekräftigeren Namen, der name war so verdorben, dass ich bezweifle, dass irgendjemand, auch als Versuch, es zu verwenden. In jedem Fall, die primäre Absicht beschränken, zu sagen dem compiler, dass es sich nicht um einen alias zu diesem Artikel.Ein Grund dafür ist es, die Dinge werden in Registern gespeichert vorübergehend.Betrachten Sie zum Beispiel etwas wie: Der compiler wirklich setzen will ich in ein register, und laden *ein in ein register, so dass, wenn es darum geht, Zeit, um zu entscheiden, ob zum ausführen einer anderen iteration der Schleife, die es nur vergleicht die Werte in diese Register zu einander.Leider kann es nicht tun-wenn jemand, verwendet diese Funktion war völlig verrückt, und bezeichnet es mit a==b, jedes mal, wenn Sie schreibt zu *b innerhalb der Schleife, der neue Wert ist auch der Wert von *a-also, es zu Lesen hat *eine aus dem Speicher bei jeder iteration der Schleife, nur für den Fall, wer auch immer es genannt wurde, völlig verrückt.Die Verwendung einschränken, sagt der compiler kann code generieren, vorausgesetzt, dass a und b wird immer unterschiedlich sein, so schreiben *eine wird sich nie ändern *b (oder Umgekehrt).restrict
Schlüsselwort und seine Auswirkungen auf die Leistung endlich und
void f(int *a, int *b, int *c) {
for (int i=0; i<*a; i++)
*b += c[i];
}
Ihr Verständnis ist weitgehend richtig. Die restrict
Qualifier besagt einfach, dass die durch einen so qualifizierten Zeiger zugegriffen Daten nur von genau dieser Zeiger abgerufen. Es gilt für liest als Brunnen als schreibt.
Der Compiler kümmert sich nicht um gleichzeitige Threads, war es anders nicht geht Code zu generieren, und Sie können Ihre eigenen Daten verprügeln, wie Sie möchten. Aber es muss wissen, welche Zeigeroperationen ändern können, was den globalen Speicher.
Restrict
trägt auch mit ihm eine API-Warnung für die Menschen, die eine gegebene Funktion mit der Annahme unaliased Parameter durchgeführt wird.
Keine Sperren durch den Benutzer notwendig ist, so weit wie der Compiler geht. Sie will nur sicherstellen, dass es richtig Daten liest, die war sollte von Code verprügelt, wird die Compiler generieren sollte , falls es kein restrict
Qualifier. Hinzufügen restrict
befreit es von dieser Sorge.
Schließlich ist zu beachten, dass der Compiler wahrscheinlich ist bereits möglich Aliasing auf Datentypen anhand der Analyse sein, bei den höheren Optimierungsstufen, so restrict
ist wichtig, vor allem für Funktionen mit mehreren Zeigern auf die gleiche Art von Daten. Sie können eine Lehre aus diesem Thema nehmen und stellen Sie sicher, dass jede vorsätzliche Aliasing Sie über eine union
erfolgt tun.
Wir können restrict
in Aktion sehen:
void move(int *a, int *b) { void move(int *__restrict a, int *__restrict b) {
a[0] = b[0]; a[0] = b[0];
a[1] = b[0]; a[1] = b[0];
} }
movl (%edx), %eax movl (%edx), %edx
movl %eax, (%ecx) movl %edx, (%eax)
movl (%edx), %eax movl %edx, 4(%eax)
movl %eax, 4(%ecx)
In der rechten Spalte, mit restrict
, der Compiler nicht brauchte b[0]
aus dem Speicher neu zu lesen. Es war in der Lage b[0]
und halten Sie sie im Register %edx
zu lesen, und speichern Sie dann nur das Register zweimal in dem Speicher. In der linken Spalte, wußte es nicht, wenn der Laden zu a
hat b
geändert werden.
Jemand vertrauter mit dem Standard wahrscheinlich eine bessere Antwort geben könnte, aber ich werde es ein Schuss.
„Die Daten werden nicht hinter dem Rücken des Compiler modifiziert werden“ klingt wie das Gegenteil von „flüchtig“ zu mir.
„const“ bedeutet, dass die Daten nicht vor dem Programmierer verändert werden; das heißt, sie kann nicht die Daten über die Signifikanten ändern als „const“ markiert (ich schreibe „Signifikant“, weil in int const *pi
, wird der Name pi
nicht const, aber *pi
ist). Die Daten könnten über einen anderen Signifikanten modifizierbar sein (nicht konstante Daten können auf eine Funktion als const Daten weitergegeben werden, nachdem alle).
Der „beschränken“ qualifiziert Zeiger ist der Schlüssel. Zeiger sind der einzige Weg, um Alias-Daten in C, so dass sie die einzige Möglichkeit, dass Sie einig Stück von Daten über zwei verschiedene Namen zugreifen können. „Beschränkt“ dreht sich alles um den Datenzugriff auf einen Zugriffspfad zu begrenzen.
Dies könnte ein Beispiel aus einer extrem schmal Domäne, aber Altera Nios II-Plattform ist ein Soft-Core-Mikrocontroller, die Sie innerhalb eines FPGA anpassen können. Dann in dem C-Quellcode für dieses Mikro, können Sie ein C-to-Hardware-Tool verwenden, um innere Schleifen mit benutzerdefinierter Hardware zu beschleunigen, anstatt in der Software.
dort Verwendung des __restrict__
Schlüsselwort (die die gleiche wie C99 des restrict
ist) ermöglicht es dem C2H Werkzeug, um richtig die Hardwarebeschleunigung des Zeigers Betrieb zu optimieren parallel statt sequentiell. Zumindest in diesem Fall ist die restrict
einfach nicht für den menschlichen Verzehr gedacht. Siehe auch Suns Seite auf restrict
, wo die erste Zeile sagt
Mit dem
restrict
Qualifier in geeigneter Weise in C-Programmen erlauben kann der Compiler wesentlich schneller ausführbare Dateien zu erzeugen.
Wenn jemand interessiert ist Lesen Sie mehr auf C2H, diese PDF bespricht die Optimierung C2H Ergebnisse. Der Abschnitt über __restrict__
ist auf Seite 20.