2013-04-05 2 views
6

Einige Leute sagten: "Jede Operation, die durch Arrays Subskribierung erreicht werden kann, kann auch mit Zeigern erfolgen. Die Zeigerversion wird im Allgemeinen schneller sein".Effizienz zwischen Zeiger und Array (weniger Montageanweisungen dauert nicht weniger Zeit)

Ich bezweifle, über das Ergebnis der oben genannten, so dass ich den folgenden Test:

Im folgenden Artikel, Wir kümmern uns nicht Compiler-Optimierung. Über Compiler-Optimierung, wie die Effizienz zwischen Zeiger und Array beeinflussen, bitte beachten Sie: Efficiency: arrays vs pointers

(Visual Studio 2010, Debug-Modus, keine Optimierungen)

#include <windows.h> 
#include <stdio.h> 

int main() 
{ 
    int a[] = {10,20,30}; 
    int* ap = a; 

    long counter; 

    int start_time, end_time; 
    int index; 

    start_time = GetTickCount(); 
    for (counter = 1000000000L; counter>0; counter--) 
    { 
     *(ap+1) = 100; 
    } 
    end_time = GetTickCount(); 
    printf("10 billion times of *ap = %d\n", end_time-start_time); 

    start_time = GetTickCount(); 
    for (counter = 1000000000L; counter>0; counter--) 
    { 
     a[1] = 101; 
    } 
    end_time = GetTickCount(); 
    printf("10 billion times of a[0] = %d\n", end_time-start_time); 

    return 0; 
} 

das Ergebnis:

10 billion times of *ap = 3276 
10 billion times of a[0] = 3541 

Der Zeiger scheint ein wenig schnell zu sein. Aber nachdem ich die verglichenen dis zusammenbauen, ich in eine tiefere Verwirrung fiel.

(Visual Studio 2010, Debug-Modus, keine Optimierungen)

; 17 :   *(ap+1) = 100; 
mov eax, DWORD PTR _ap$[ebp] 
mov DWORD PTR [eax+4], 100   ; 00000064H 

; 25 :   a[1] = 101; 
mov DWORD PTR _a$[ebp+4], 101  ; 00000065H 

Vom Ausgang montieren, Speicherzugriff über einen Zeiger nimmt 2 Anweisungen und Array benötigt nur 1 Befehl.

Warum Array weniger Anweisungen ausführen, aber es dauert nicht weniger Zeit als Zeiger?

Ist es mit dem CPU-Cache verbunden? Wie kann ich meinen Testcode ändern, um dies zu beweisen?

+6

nie im Debug-Modus optimieren ... – TemplateRex

+2

Vor vielen Jahren habe ich genau das getestet. Die Array-Indizierung war schneller. Die Aussage ist Quatsch, entweder könnte es schneller sein, es kommt nur darauf an. – john

+0

Es hängt nur ... auf Hardware? – Philip

Antwort

2

Erstens und am wichtigsten, die Sprache C hat keine Geschwindigkeit. Das ist ein Attribut, das durch Implementierungen von C eingeführt wird. Zum Beispiel hat C keine Geschwindigkeit, aber der GCC-Compiler produziert Code, der in seiner Geschwindigkeit vom Code des Clang-Compilers abweichen kann, und beide produzieren wahrscheinlich Code, der führt das von den Cint- oder Ch-Interpreten erzeugte Verhalten aus. All dies sind C-Implementierungen. Einige von ihnen sind langsamer als andere, aber die Geschwindigkeit kann nicht zu C in sowieso zugeschrieben werden!

6.3.2.1 des Standard C sagt:

Außer wenn es der Operand des sizeof-Operator, der _Alignof Operator oder der unären & Operator oder ein Stringliteral verwendet initialisieren Sie ein Array, ein Ausdruck, der Typ '' Array des Typs '' ist in einen Ausdruck mit Typ '' Zeiger auf den Typ '' konvertiert, die auf das ursprüngliche Element des Array-Objekts zeigt und ist kein Lvalue.

Dies sollte ein Hinweis darauf sein, dass sowohl *(ap+1) und a[1] in Ihrem Code sind Zeigeroperationen. Diese Übersetzung wird während der Kompilierungsphase in Visual Studio ausgeführt. Daher sollte dies keinen Einfluss auf die Laufzeit haben.

6.5.2.1 in Bezug auf „Array Indizierung“ sagt:

einer der Ausdrücke soll Typen ‚‘ Zeiger auf Objekt Typen Full ‚hat‘, so haben die anderen Expressions Integer-Typen haben, und das Ergebnis hat Typen ' 'Art''. Dies scheint darauf hinzudeuten, dass der Array-Index Operator tatsächlich ein Zeiger-Operator ist ...

Dies ist eine Bestätigung, dass ap[1] ist in der Tat eine Zeiger Operation, wie wir früher postulierten. Zur Laufzeit wurde das Array jedoch bereits in einen Zeiger übersetzt. Die Leistung sollte identisch sein.

... also, warum sind sie nicht identisch?

Was sind die Merkmale des von Ihnen verwendeten Betriebssystems? Ist es kein Multitasking-Betriebssystem für mehrere Benutzer? Angenommen, das OS würde die erste Schleife ohne Unterbrechung abschließen, aber dann die zweite Schleife unterbrechen und die Steuerung in einen anderen Prozess umschalten. Würde diese Unterbrechung Ihr Experiment nicht ungültig machen? Wie messen Sie die Häufigkeit und das Timing von Unterbrechungen, die durch Taskwechsel verursacht werden? Beachten Sie, dass dies für verschiedene Betriebssysteme unterschiedlich ist und dass das Betriebssystem Teil der Implementierung ist.

Was sind die Eigenschaften der verwendeten CPU? Hat es einen eigenen schnellen internen Cache für Maschinencode? Angenommen, Ihre gesamte erste Schleife und ihr umfassender Timing-Mechanismus sollten gut in den Code-Cache passen, aber die zweite Schleife wurde abgeschnitten. Würde dies nicht dazu führen, dass ein Cache fehlschlägt, und lange warten, während Ihre CPU den Rest des Codes aus dem RAM holt? Wie misst man das Timing von Unterbrechungen, die durch Cache-Misses verursacht werden? Beachten Sie, dass dies für verschiedene CPUs unterschiedlich ist, und die CPU ist Teil der Implementierung.

Diese Fragen sollten einige Fragen aufwerfen wie: "Löst dieser Mikrooptimierungs-Benchmark ein bedeutungsvolles oder wichtiges Problem?". Der Erfolg einer Optimierung hängt von der Größe und Komplexität des Problems ab. Finden Sie ein wichtiges Problem, lösen Sie es, profilieren Sie die Lösung, optimieren Sie sie und profilieren Sie sie erneut. Auf diese Weise können Sie aussagekräftige Informationen über geben, um wie viel schneller die optimierte Version ist. Ihr Chef wird viel glücklicher mit Ihnen sein, vorausgesetzt, Sie geben nicht bekannt, dass die Optimierungen wahrscheinlich nur für Ihre Implementierung relevant sind, wie ich bereits erwähnt habe. Ich bin sicher, Sie werden feststellen, dass die geringste Ihrer Sorgen Array Dereferenz vs Zeiger Dereferenz sein wird.

+0

@GrijeshChauhan Danke. Ich schätze die Formatierung, aber die anderen Änderungen waren entweder falsch oder unbedeutend. Ich meinte "[cint] (http://root.cern.ch/drupal/content/cint)". Es gibt zwei korrekte Möglichkeiten, "Verhalten" zu buchstabieren: [Die amerikanisch-englische Art] (http://www.merriam-webster.com/dictionary/behavior), und [die britische Art] (http: //www.merriam -webster.com/dictionary/behaviour). Bitte, machen Sie sich nicht die Mühe, das zu korrigieren. Sie werden am Ende Arthritis schneller als Sie realisieren ... – Sebivor

+0

Ooh ... Sorry für das .. Es war versehentlich..BTW nette Erklärung So nahm ich Interesse. –

+0

@lvalue Das unterschiedliche Ergebnis wird möglicherweise durch CPU-Cache beeinflusst, aber wie kann es beweisen? – ajaxhe