C++ | Wenn IF-Anweisung klappt schließt sich das Programm

VS unterstützt wohl void weil das in C soweit auch ok ist.
In C++ aber nicht wirklich, und da erlaubt es VS auch.

Siehe "or in some other implementation-defined manner."
Ach, wenn es nur so wäre.
VS behandelt void halt eben nicht als void. Ich deute es eher als Versuch seitens MS, die Logik auf C-Ebene wieder geradezubiegen: "Was, eine int-Funktion ohne Rückgabewert? Das darf nicht sein. Nennen wir es void und setzen EAX einfach selbst auf 0". Denn void heisst für Sprachen höher als ASM schlicht: "Ich habe dir nichts zu geben". In ASM heisst es hingegen: "Ich tue nichts mit dem EAX-Register".


Die meisten der Mikrooptimierungen, die sich auf ASM-Code berufen funktionieren meistens nur im Debugmodus, im Releasemodus funkt dir der Optimierer in Echtweltsituationen viel zu stark dazwischen. Die Signatur einer Funktion sollte nicht durch Optimierungen bestimmt werden sondern durch die durch die Architektur gegebenen Kriterien.
Stimmt. Dennoch gibt es einen Grund, weshalb einige Funktionen noch von Hand gemacht werden (z.B. memcpy, strcpy etc.). Natürlich ist das mischen dieser beiden Codes zwischen Funktionen brandgefährlich, manchmal ist inline ASM aber dennoch Gold wert.

Ich würde mir die Optimierungen zwar gerne ansehen, aber VS erlaubt die Breakpoints ein bisschen wenig :(

Wobei der Optimierer auch nicht wirklich zu C selbst gehört; es ist schlicht eine nette Dreingabe. Wobei die Optimierer meist ein Buch mit sieben Siegeln sind :/

Gruss
cwriter

/EDIT: Antwort an sheel zur Vermeidung des Doppelposts

Muss gerade wieder an unsere PN-Unterhaltung wegen VS denken :)
Dito :)

Naja, main ist ja auch so, ohne Asm, nicht exakt wie andere Funktionen.
Hm? Es ist die Hauptfunktion, der Rumpf sozusagen, und wird immer ausgeführt. Was ist sonst noch anders?
Warum sollte es also 100% gleich behandelt werden?
Ein Beispiel wäre z.B. die Wiedernutzung in einer DLL oder einer LIB. Beispielsweise, wenn die main das Interface initialisiert, ist dies nicht mal unwahrscheinlich. Oder ein Server, der früher in der main gestartet wurde und nun direkt, so wie er ist, eingebunden werden soll.

Andererseits schaffen sie es ja nicht einmal, C99 endlich voll zu unterstützen. Immerhin wird daran gearbeitet, 16 Jahre später...
Wobei g++ bei C++11 hinterherhinkt. Stichwort "-std=c++11". Ich glaube nicht, dass auf der Welt auch nur ein Standard existiert, an den sich alle halten.

Mir ist leider noch nicht ganz klar worauf die hinauswillst :/
Es geht mir um eine unnötige Inkonsistenz. Man spart, wie gesagt, fast nichts, wenn man das "return 0" weglässt. Dafür hat man damit grosse Probleme, wenn die Programme ein bisschen komplexer werden. Man nimmt mit dem Weglassen einer kurzen Zeile somit einige weitere Instruktionen in Kauf, die schlicht nicht sein müssten. Dieses Problem hat nicht nur VS, sondern wohl jeder Compiler (ich habe gerade kein Linux mit entsprechenden Tools zur Hand, vielleicht kann ja jemand die Codes oben durch gcc oder g++ jagen und die Ergebnisse anschauen). Es würde mich doch sehr erstaunen, würden die Ergebnisse massiv abweichen.

Ob EAX bei void in Ruhe gelassen wird hängt auch sehr vom Compiler ab, garantiert ist es nicht.
Es gibt aber auch keinen Grund, EAX zu verändern. Eher im Gegenteil: Wozu unnötige Instruktionen ausführen? Dann ist EAX halt mal undefined. Es besteht kein Risiko, da EAX eines der volatilsten Register ist, und man davon eigentlich nur direkt nach einem Schreibvorgang lesen sollte. void war schon immer nur als Platzhalter gedacht. Aber wie gesagt: Man sollte es nicht tun, und wenn, dann sicher ohne Optimierer.

Zu Lehre 3: Dass Asm im C-Standard als nicht-existent betrachtet wird (so wie Computer usw., wenn ich mich richtig erinnere), dürfte einer der Gründe für die weite Verbreitung sein :) = Dass es eben sehr wenig Vorgaben an Gerät und Umgebung macht und damit so ziemlich überall einsatzfähig ist.
Das würde ich nicht so sehen. C ist stark abhängig von ASM, aber nicht von der Hardware. Es ist schlicht mehr oder weniger portabler Code, der für viele Systeme gleich funktioniert, aber die Compiler machen daraus dennoch ASM. Daher: Was in ASM nicht möglich ist, geht auch nicht in C. Oder, mit einer berühmt-berüchtigten Auto-Analogie: Wenn der ungepolstere Rohbau es nicht den Berg hinauf schafft, dann schafft es derselbe Wagen mit Ledersitzen auch (oder gar "erst recht") nicht.

(aber auf jeden Fall ist es eine schöne Beschäftigung, auf der Ebene herumzuspielen :D)
Das sicherlich :)

Gruss
cwriter
 
Zuletzt bearbeitet:
Main:
main müsste theoretisch nicht einmal als abgetrennte Funktion in Asm existieren; irgendwo im Std ist es nämlich auch verboten es selbst aufzurufen. Oder Aufbauzeug von Konsole usw. kann reingemischt werden, etc.etc.

GCC und std=c++11 :
Eben, GCC kanns wenigstens auf Wunsch, im Gegensatz zu VS :p Egal ob C99, C11, C++11, C++14... es ist zwar "mehr" möglich, aber kein gefordertes Feature fehlt (außer es ist noch nicht implementiert, was aber vergleichsweise schnell geht. zB. C++14 schaut vollständig aus)
(Disclaimer: Ja, seit ich die GCC-Linie richtig kennengelernt habe liebe ich sie :) MinGW hat zwar seine eigenen Kompatibilitätsprobleme auf Windows, und ganz ohne VS gehts da nicht, aber ich meide es wenn möglich)

C ist abhängig von Asm:
Irgendwie meinen wir das Gleiche :) C macht möglichst wenig Beschränkungen an alles darunter. damit es möglichst portabel ist; und wird gerätespezifisch in Asm umgesetzt, weil es sowieso keine wirklich andere Möglichkeit gibt. Aber es schreibt eben nicht vor, dass es etwas Asm-artiges auf einem VonNeumann-Computer sein "muss". Es wäre nach heutigen Standard ebenso erlaubt, dass die rohen Befehle aus Eiweißreaktionen in einen biologisch lebenden Ding bestehen. C ist da absichtlich möglichst extrem abstrakt, und will möglichst wenig Abhängigkeiten von "üblichen" Systemen (welches Level von "üblich" auch immer gemeint ist)

Und zu der Sache, ob GCC das mit dem impliziten Return besser umsetzt:
Ja, 1:0 GCC:VS :p
Hab nicht alle Szenarios von oben genommen, nur was ganz Einfaches:
C++:
int main()
{
}
und
C++:
int main()
{
	return 0;
}
auf MinGW 4.9.1, mittlere Optimierungsstufe (O2), sonst nichts (außer Flag für Asm-Ausgabe)
liefert den exakt gleichen Output:
Code:
	.file	"a.cpp"
	.def	___main;	.scl	2;	.type	32;	.endef
	.section	.text.startup,"x"
	.p2align 4,,15
	.globl	_main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	pushl	%ebp
	movl	%esp, %ebp
	andl	$-16, %esp
	call	___main
	xorl	%eax, %eax
	leave
	ret
	.ident	"GCC: (i686-posix-sjlj-rev0, Built by MinGW-W64 project) 4.9.1"

@DeThPy: Sorry, wir sind sehr abgeschweift :)
 
Zuletzt bearbeitet:
Und zu der Sache, ob GCC das mit dem impliziten Return besser umsetzt:
Ja, 1:0 GCC:VS :p
Hab nicht alle Szenarios von oben genommen, nur was ganz Einfaches:
Inwiefern ist das besser?
Code:
int main()
{
010C1420  push        ebp  
010C1421  mov         ebp,esp  
010C1423  sub         esp,0C0h  
010C1429  push        ebx  
010C142A  push        esi  
010C142B  push        edi  
010C142C  lea         edi,[ebp-0C0h]  
010C1432  mov         ecx,30h  
010C1437  mov         eax,0CCCCCCCCh  
010C143C  rep stos    dword ptr es:[edi]  
   
}
010C143E  xor         eax,eax  
010C1440  pop         edi  
010C1441  pop         esi  
010C1442  pop         ebx  
010C1443  mov         esp,ebp  
010C1445  pop         ebp  
010C1446  ret
Ist so ziemlich dasselbe, würde ich sagen.
Interessant würde es erst bei diesem Code:
C++:
int main()
{
    volatile int one = 1;
    volatile int two = 2;

    if (one == two)
    {
        return 10;
    }
    else
    {
       
    }
}

Gruss
cwriter
 
Hmm...scheinbar hab ich keine Ahnung mehr, was wer eigentlich zeigen will.
Sorry, aber ich les mir das morgen wieder gründlich durch ( :gähn: )

edit: Noch kurz der Asm-Output:
Code:
	.file	"a.cpp"
	.def	___main;	.scl	2;	.type	32;	.endef
	.section	.text.startup,"x"
	.p2align 4,,15
	.globl	_main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	pushl	%ebp
	movl	%esp, %ebp
	andl	$-16, %esp
	subl	$16, %esp
	call	___main
	movl	$1, 8(%esp)
	movl	$2, 12(%esp)
	movl	8(%esp), %edx
	movl	12(%esp), %eax
	leave
	cmpl	%eax, %edx
	movl	$0, %edx
	movl	$10, %eax
	cmovne	%edx, %eax
	ret
	.ident	"GCC: (i686-posix-sjlj-rev0, Built by MinGW-W64 project) 4.9.1"
 
Interessant würde es erst bei diesem Code:
C++:
int main()
{
    volatile int one = 1;
    volatile int two = 2;

    if (one == two)
    {
        return 10;
    }
    else
    {
     
    }
}

Gruss
cwriter

Passt bei mir in VS sehr gut im Releasemode, macht der Compiler zu folgendem Code:
C:
int main() {
   volatile int one = 1;
   volatile int two = 2;
   return (one == two) ? 10 : 0;
}

Oder Assembler:
Code:
push        ebp 
mov         ebp,esp
sub         esp,8  
mov         dword ptr [ebp-8],1 
xor         eax,eax 
mov         dword ptr [ebp-4],2 
mov         edx,dword ptr [two]
mov         ecx,dword ptr [one]
cmp         ecx,edx
push        esi 
mov         esi,0Ah 
cmove       eax,esi  
pop         esi 
mov         esp,ebp 
pop         ebp 
ret
 
Hmm...scheinbar hab ich keine Ahnung mehr, was wer eigentlich zeigen will.
Kurz zusammengefasst: Implizites return 0 = böse :)

Aber Cromon ist mal wieder unerbittlich und zerreisst meine Argumente in der Luft :(
Passt bei mir in VS sehr gut im Releasemode, macht der Compiler zu folgendem Code:
Ja, der Optimierer springt ein. Somit habe ich dann wohl keine Argumente übrig, ausser das Inkonsistenz-Dingens.

Ich gebe auf. Mein letzter Versuch wäre gewesen, eine Lambda-Funktion daraus zu kreieren, die einen automatischen Rückgabetyp hat, aber main kann man ziemlich schlecht in eine Lambda packen :p

Ich kann nur noch eine Analogie mit Deutsch versuchen: Kommas vor Infinitivsätzen sind zwar fakultativ, aber schöner. Genau wie ein return 0 in der main.

Aber ja. Der Code ist mit implizitem return 0 vollkommen korrekt, portabel und funktioniert zumindest optimiert gleich gut wie ein explizites return 0.

Asche auf mein Haupt
cwriter
 
Zurück