Beschränken mit Arrays verwenden?

Lesezeit: 5 Minuten

Benutzeravatar von Piotr Lopusiewicz
Piotr Lopusiewicz

Gibt es eine Möglichkeit, einem C99-Compiler mitzuteilen, dass die einzige Möglichkeit, auf ein bestimmtes Array zuzugreifen, die Verwendung von myarray ist[index] ? Sagen Sie so etwas:

int heavy_calcualtions(float* restrict range1, float* restrict range2)
{
    float __I promise I won't alias this__ tmpvalues[1000] = {0};

    ....
    heavy calculations using range1, range2 and tmpvalues;
    ....
}

Durch die Verwendung von “restrict” habe ich versprochen, dass ich nicht “range1” und “range2” aliasiere, aber wie mache ich dasselbe für das in meiner Funktion deklarierte Array?

  • Welche Art von Warnung wirft es aus?

    – dhein

    28. September 2013 um 8:56 Uhr

  • “Ungültige Verwendung von Restrict” – es soll mit Zeigern verwendet werden, nicht mit Arrays (soweit ich verstehe). Ich könnte Float* Restrict tmpvalues ​​= malloc(sizeof(float)*1000) tun, aber dann weise ich nicht auf dem Stack zu, was die Leistung ebenfalls beeinflussen kann. Abgesehen davon, dass einem Compiler mitgeteilt wird, dass der Zugriff auf Array-Indizes sicher ist (also keine defensiven Lesevorgänge erforderlich sind), scheint dies eine sehr natürliche Erweiterung der Verwendung von Beschränkungen mit Zeigern zu sein, so dass es intuitiv einen Weg geben muss, dies zu tun.

    – Piotr Lopusiewicz

    28. September 2013 um 15:50 Uhr


  • Ich habe: Float* Restrict tmpvalues ​​= alloca(sizeof(float)*1000); memset(tmpvalues, 0, sizeof(float)*1000); und es ist eine messbare Verbesserung, aber ich würde es vorziehen, es im Standard zu tun (wie in C99-Beschwerdeweise)

    – Piotr Lopusiewicz

    28. September 2013 um 17:23 Uhr

  • @PiotrLopusiewicz kannst du wo einen aktuellen Code posten float *restrict tmpvalues übertrifft die VLA? (vorzugsweise mit bereits vorhandenem Timing-Code)

    – MM

    23. Mai 2014 um 3:30 Uhr

  • Greifen Sie mit einem Beschränkungszeiger auf das Array zu.

    – Jeff Hammond

    26. April 2015 um 1:03 Uhr

Benutzeravatar von Harald
Harald

Obwohl Jeffs Antwort richtig ist, dh Sie können immer einen Zeiger auf das zugewiesene Array machen, ist die Tatsache, dass der Compiler weiß zur Kompilierzeit, dass tmpvalues ​​kein Aliasing erhalten, da die Variable als tatsächliches Array und nicht als Zeiger deklariert wird. Die einzige Möglichkeit, ein Array mit einem Alias ​​zu versehen, besteht darin, einen Zeiger darauf zu deklarieren. Wenn Sie dies nicht tun, müssen Sie es nicht so deklarieren restrict. Dies wird deutlicher, wenn tmpvalues ist die einzige Variable, die Sie innerhalb der Funktion haben.

Das Problem kann auftreten, wenn Sie den Zeiger an eine andere Funktion übergeben, dann sollten Sie dort angeben, ob der empfangene Zeiger eingeschränkt ist oder nicht.

Die Dokumentation, auf die ich zu diesem Thema gestoßen bin, enthält die C99:

Sei D eine Deklaration eines gewöhnlichen Bezeichners, der ein Mittel bereitstellt, um ein Objekt P als einen eingeschränkt qualifizierten Zeiger auf den Typ T zu bezeichnen.

Beachten Sie, dass dies nur für Zeiger gilt.

Dieses andere Dokument von TI bietet einige Hinweise zur Leistungsoptimierung mithilfe von restrict Stichwort. Zusätzlich zu allen Hinweisen enthält Abschnitt 3.3 Beispiele, wann es möglich ist, diesen Typqualifizierer anzuwenden und wann nicht. Suche nach x Array-Deklaration in der Mitte von Seite 16 heißt es, dass es keinen Zeiger deklariert und daher auch nicht sein kann restrict-qualifiziert.

  • Wenn ein Zeiger auf das Array an externen Code übergeben wird, gibt es keine saubere Möglichkeit anzugeben, dass externer Code keine Kopie des Zeigers behält und diese Kopie beim nächsten Aufruf von externem Code für willkürliche Zwecke verwendet. IMHO wäre es für C hilfreich gewesen, einen ähnlichen Qualifizierer zu haben restrict aber für die Verwendung mit Variablen, deren Adresse genommen wurde, aber nur auf sehr begrenzte Weise verwendet wird, aber keine solche Funktion definiert ist.

    – Superkatze

    7. September 2016 um 23:14 Uhr


  • @supercat ein Problem ist – wie definieren Sie diese “verschiedenen Wege”? gcc hat Attribute (wie „pure“), die an Funktionen angehängt werden können, die versprechen, dass die Funktion bestimmte Klassen von Dingen nicht tut. Darüber hinaus haben wir jetzt eine „Linkzeitoptimierung“, bei der das Compiler-Toolset im Grunde nachsehen kann, was die Funktion tatsächlich tut, und diese Informationen verwenden kann.

    – Gregor

    17. Mai 2017 um 14:49 Uhr

  • @greggo: Wenn ich die Regeln schreiben würde, würde ich sagen, dass a register-qualifiziertes Objekt darf seine Adresse nur bei der Auswertung eines Funktionsarguments verwenden, und das Verhalten würde nur in Fällen definiert werden, in denen alle Verwendungen des resultierenden Zeigers oder davon abgeleiteter Zeiger vor der Rückkehr der Funktion und während der Ausführung der Funktion entweder ( 1) auf das Objekt wird ausschließlich über resultierende Zeiger oder andere davon abgeleitete Zeiger zugegriffen, oder (2) das Objekt wird auf keine Weise modifiziert. Wenn ein Build-Prozess mit dem Erstellen einer Liste aller externen Symbole beginnt, die in jeder Funktion verwendet werden …

    – Superkatze

    17. Mai 2017 um 16:50 Uhr

  • …ein Compiler könnte mit Sicherheit davon ausgehen, dass, wenn weder “foo” noch eine von “foo” aufgerufene Funktion das Symbol “bar” verwendet, das einem registerqualifizierten Objekt zugeordnet ist, Zugriffe auf “bar” als nicht sequenziell relativ behandelt werden können auf alles, was innerhalb der Funktion auftritt [the definition of every function with a given signature would be regarded as a call from a generic function of that signature type to that function, and an indirect call to a pointer of a signature type would be a call to a generic function of that type, and thus a call to every function matching that signature].

    – Superkatze

    17. Mai 2017 um 16:54 Uhr

Benutzeravatar von Jeff Hammond
Jeff Hammond

Warum können Sie Folgendes nicht tun? Sie greifen nicht auf die damit verbundenen Daten zu tmpvalues über diese Variable, daher ist es gültig, einen Einschränkungszeiger im rechenintensiven Teil des Codes zu verwenden.

#include <stdio.h>
#include <stdlib.h>

int heavy_calcs(int n, float* restrict range1, float* restrict range2)
{
    if (n>1000) return 1;
    float tmpvalues[1000] = {0};
    {
        float * restrict ptv = tmpvalues;
        for (int i=0; i<n; i++) {
            ptv[i] = range1[i] + range2[i];
        }
    }
    return 0;
}

int main(int argc, char * argv[])
{
    int n = (argc>1) ? atoi(argv[1]) : 1000;
    float * r1 = (float*)malloc(n*sizeof(float));
    float * r2 = (float*)malloc(n*sizeof(float));
    int rc = heavy_calcs(n,r1,r2);
    free(r1);
    free(r2);
    return rc;
}

Ich habe dies durch den Intel 15-Compiler laufen lassen und es hatte keine Probleme, die Schleife zu vektorisieren. Zugegeben, diese Schleife ist im Vergleich zu Ihrer, wie ich annehme, trivial, daher kann Ihre Laufleistung variieren.

  • Keine Notwendigkeit, das Ergebnis zu werfen malloc in C

    – phuklv

    25. August 2016 um 7:58 Uhr

  • Es besteht keine Notwendigkeit für die {} um die ptv Auftrag auch nicht.

    – Jeff Hammond

    29. August 2016 um 3:54 Uhr

1432330cookie-checkBeschränken mit Arrays verwenden?

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

Privacy policy