2016-07-01 7 views
2

[Update] 2016.07.02eine Standardfunktion Aufschalten verhält sich unerwartet

main.c

#include <stdio.h> 
#include <string.h> 

size_t strlen(const char *str) { 
    printf("%s\n", str); 
    return 99; 
} 
int main() { 
    const char *str = "AAA"; 
    size_t a = strlen(str); 
    strlen(str); 
    size_t b = strlen("BBB"); 
    return 0; 
} 

die erwartete Ausgabe ist

AAA 
AAA 
BBB 

Compilieren mit gcc -O0 -o Haupt main. c:

AAA 

Kompilieren mit gcc h -O3 -o Haupt main.c

AAA 
AAA 

Der entsprechende Code mit ASM-Flag -O0

000000000040057c <main>: 
40057c: 55      push %rbp 
40057d: 48 89 e5    mov %rsp,%rbp 
400580: 48 83 ec 20    sub $0x20,%rsp 
400584: 48 c7 45 e8 34 06 40 movq $0x400634,-0x18(%rbp) 
40058b: 00 
40058c: 48 8b 45 e8    mov -0x18(%rbp),%rax 
400590: 48 89 c7    mov %rax,%rdi 
400593: e8 c5 ff ff ff   callq 40055d <strlen> 
400598: 48 89 45 f0    mov %rax,-0x10(%rbp) 
40059c: 48 c7 45 f8 03 00 00 movq $0x3,-0x8(%rbp) 
4005a3: 00 
4005a4: b8 00 00 00 00   mov $0x0,%eax 
4005a9: c9      leaveq 
4005aa: c3      retq 
4005ab: 0f 1f 44 00 00   nopl 0x0(%rax,%rax,1) 

und mit -O3:

0000000000400470 <main>: 
400470: 48 83 ec 08    sub $0x8,%rsp 
400474: bf 24 06 40 00   mov $0x400624,%edi 
400479: e8 c2 ff ff ff   callq 400440 <[email protected]> 
40047e: bf 24 06 40 00   mov $0x400624,%edi 
400483: e8 b8 ff ff ff   callq 400440 <[email protected]> 
400488: 31 c0     xor %eax,%eax 
40048a: 48 83 c4 08    add $0x8,%rsp 
40048e: c3      retq 

mit der Flagge -O0, Warum ruft der zweite und dritte Aufruf von strlen nicht den benutzerdefinierten strlen an?

Und mit -O3, warum ist der dritte Aufruf zu Strlen optimiert worden?

+1

Wahrscheinlich, weil der Compiler die redundanten Aufrufe optimiert hat, aber das ist ein bisschen seltsam, wenn man bedenkt, dass es Nebenwirkungen in Ihrer Implementierung hat. Nicht sicher, wie weit es mit bekannten Funktionen wie 'strlen()' gehen wird. Einzelschritt den Code in einem Debugger. – unwind

+0

Angenommen, dies ist gcc, versuchen Sie, es mit '-fno-optimize-strlen' zu kompilieren. – tofro

+1

Ändern Sie den Namen der Funktion in' my_strlen' und sehen Sie, was passiert. Und entfernen Sie 'extern' Schlüsselwort in der Funktionsimplementierung. – LPs

Antwort

0

Die wahrscheinlich eingebaute Funktion ist standardmäßig aktiviert. Wenn Sie Benutzer weise Anruffunktion definieren, dann Rückgabetyp strlen function.So ändern,

in strlen_adder.h

int strlen(const char*); 

in strlen_adder.c

int strlen(const char *s) 

Entfernen Sie auch #include<string.h> in main.c Datei.

1

GCC erkennt strlen() hat eine eingebaute und ersetzte es gebaut. Daher wird Ihre Version strlen() nicht aufgerufen.

ich Ihren Code mit -fno-builtin zusammengestellt, die die builtins deaktiviert und ich erhalte die Log in strlen Ausgabe zweimal aus dem 1. und 3. strlen() Anrufe. Wahrscheinlich wird der zweite strlen() weg optimiert, da sein Rückgabewert nicht verwendet wird. Dies passiert wahrscheinlich vor GCC erkennt, dass es das eingebaute für strlen() nicht verwenden kann. Andernfalls kann es nicht weg optimieren 2. strlen() Anruf, weil es die Nebeneffekt des Drucks der Nachricht hat.

Und falls speichern das Ergebnis der zweiten strlen() Anruf mit so etwas wie:

size_t b = strlen(str); // call 2 

dann sehe ich, "Log in strlen()" 3-mal gedruckt zu werden.

Wenn ich kompilieren mit -O3 (entweder mit oder ohne -fno-builtin), bekomme ich überhaupt keine Ausgabe, weil, wie gesagt, optimiert GCC das gesamte Programm entfernt.

Dies ist kein Problem mit GCC, weil die Neudefinition einer Standardfunktion ist technisch undefined behaviour und damit GCC hat die Freiheit behandeln es in jedem Fall.

+0

Ich möchte den benutzerdefinierten Strlen aufrufen, aber festgestellt, dass nicht alle Funktionen Aufruf an Strlen meine Funktion aufrufen wird. Meine Frage ist nicht, das Problem zu lösen, um mein Ziel zu erreichen, sondern zu verstehen, wie es funktioniert hat. – mingpepe

+1

Und eine Standardfunktion neu zu definieren ist technisch undefiniertes Verhalten. In welchem ​​Dokument haben Sie diese Information gesehen? – mingpepe

+0

'Dies passiert wahrscheinlich, bevor GCC erkennt, dass es die eingebauten Sounds nicht wie die logische Annahme hier verwenden kann. Komisch, dass es zum zweiten Mal in so vielen Tagen einen Defekt in verschiedenen Compilern gibt, die Optimierungen um String Builtins/Intrinsics beinhalten. Der andere (nicht verwandte) über "strcpy" und MSVC ist bei [ms vC++ - Compiler, der fehlerhaften Code optimiert] (http://stackoverflow.com/questions/38111158/ms-vc-compiler-optimizing-away-erroneous-code) . – dxiv

Verwandte Themen