Zeiger auf Literal



  • Außerdem habe ich keinerlei Optimierierung unter Visual Studio eingeschaltet. Es war die Standard Debug Einstellung von Visual Studio 2008 Professional.



  • Hier ein Testlauf mit den Standard Release Einstellungen von Visual Studio:

    Initializing timer ... OK
    Initializing random number generator ... OK
    Initializing test array ... OK
    Run(#    0):
    =============
    string: B›ÃøÝO$ÞÎÏ#R‡;xÐJ´x‹v8bØPáÛH̤»ä‰š âÖ3`gÑH¶Ñ(sE¦•1Œdc§Yà{ZªÞs!L¾²93K« OP3£Fc‚å+—(€lˆd”ƒSžü…ŽÆ8‚’…é²8Óhó>Ãf;¼ù“¡È~õ^IÈ\‡¹ôâ
    bgeissl: BORxJxv8bPH3gHsE1dcYZsL93KOP3FcldS88hfI ret: 0
    NDEBUG : BORxJxv8bPH3gHsE1dcYZsL93KOP3FcldS88hfI ret: 0
    
    Run(# 5000):
    =============
    string: ÒéfŸ”‹V[IéÕµl”,×!ÎûT2`&º†NÞµ:Ã#X\¶Š”è&3a~‘<6÷ño¶óÎ’8Ÿ©tûU‘ ¡›hý¹EýÅoŸÔmµüTT„P*à…QUîp²7¿Dþ×Çu•ýÈ[ã6ÑQ6¿9ʈÀÃq^‰ä^1ß¼‘ÒØË‰+K
    bgeissl: fVIlT2NX3a6o8tUhEomTTPQUp7Du6Q69q1K ret: 0
    NDEBUG : fVIlT2NX3a6o8tUhEomTTPQUp7Du6Q69q1K ret: 0
    
    Run(#10000):
    =============
    string: L;sUJK{x{Ùæz5ßF÷î?ì»Aµt™˜ÇrÁ¿ ~oèá|!‡ôékrê·åÜä³”°y.}Š7!äŽÍÀöºHOXîѪ[ ¨ˆú^°—de?Ð^ÏU9£YÇ4.Eèžö¥Ô©9»T¹%—¨œ}æúJ菦ƒW_>dû™äŠ”˜
    bgeissl: LsUJKxz5FAtr okry7HOX deU9Y4E9TJWd ret: 0
    NDEBUG : LsUJKxz5FAtr okry7HOX deU9Y4E9TJWd ret: 0
    
    Run(#15000):
    =============
    string: tyrÈrÌýdü`²õRAš×¦#¤`žê›1œúªÎ%ÅõçîRrɹ7CÓ” qšbJçΏÙw­›‘Àâ9psG®»Y…NEë›:ÈûÚ dÛtZé.(††,,7£J”ë\ q:?ãûp¢O¿‹ B,/ˆ£ôŽ¥ØéPYiõl„ѼkØ
    bgeissl: tyrrdRA1Rr7CqbJw9psGYNE dtZ7JqpOBPYilk ret: 0
    NDEBUG : tyrrdRA1Rr7CqbJw9psGYNE dtZ7JqpOBPYilk ret: 0
    
    Run(#20000):
    =============
    string: h c‚kæ÷³¨_ÚÓäb¥½€ìRwŠÅš<ž¯‰ˆò>šÉ³nùúqw„ääÆÂœ¸ƒ­ÀrúÞ[œÝî1àtlâæD×|Cå|JÍJíËç>6ZјP/­¨Eº-oÐßjiü—è*SÊ?¬1¢‰\Î(‹ï¥Æ{Š«mÍëÎàGä<B5
    bgeissl: h ckbRwnqwr1tlDCJJ6ZPEojiS1mGB5 ret: 0
    NDEBUG : h ckbRwnqwr1tlDCJJ6ZPEojiS1mGB5 ret: 0
    
    Run(#25000):
    =============
    string: )³FùDݺ€ôE¼5£‰ø4QªeOë絯ª^äû—]à,߆[Ô[¥cà5×Dl³–4‰Ãy“Ý(þ8ûÁæ)ñ;S;í¤áDg9äK.È÷±´“fEn{’£½S~'Pá@c¦Ë§‡žÓÞµœg\ûA­±\®üØ’2LÇÌ=ü·
    bgeissl: FDE54QeOc5Dl4y8SDg9KfEnSPcgA2L ret: 0
    NDEBUG : FDE54QeOc5Dl4y8SDg9KfEnSPcgA2L ret: 0
    
    Run(#30000):
    =============
    string: ˜¯kúÑÙ`j£ú¨%¹Œ½w`Œ]z dZ-WKD€PA´¢ØõÞR…`¹#èUÞ@ªè’°¼„}2Þ7.אM<»^ÍC¸4\`è6Èz*µ“pÈ€iùQÓ·E‘ö£0ŒIŽe¿)q\¶Ã–u°c‡FE&œ'YC§N¡{{âSxŒˆo@ê
    bgeissl: kjwzdZWKDPARU27MC46zpiQE0IequcFEYCNSxo ret: 0
    NDEBUG : kjwzdZWKDPARU27MC46zpiQE0IequcFEYCNSxo ret: 0
    
    Run(#35000):
    =============
    string: @d‚“îpÂñ0˜òûí¤FÊšf’8úpj.†tq›¯Ì©Yž7m˜ ÛQ‡Û•‰³"ùŸv{=™¯M2×F‘óÆÕã÷ý§rô,È7BPJTÞþFîi!œ‚XÑêCÒMøæ^GÆõïÉÚErŸØ4’3=‰[k­£@n—¦ã/{j‚fÍ
    bgeissl: dp0Ff8pjtqY7mQvM2Fr7BPJTFiXCMGEr43knjf ret: 0
    NDEBUG : dp0Ff8pjtqY7mQvM2Fr7BPJTFiXCMGEr43knjf ret: 0
    
    Run(#40000):
    =============
    string: HµŠ˜™î¶æröJRéÅ«k¼ښ`&–±V‹†ªË,?IĴý”¯kÇówºœCxŸêžÑ9”^]OM”­=ñǺHYyoªØjwë…vºHU}˜‡¤¤î똓dÃ?‡MDÜEÃL¥ËûF2¤'*Š>j¤ž«ÛB06 3J»¦B 3Ýò
    bgeissl: HrJRkVkwCx9OMHYyojwvHUdMDELF2jB06 3JB 3 ret: 0
    NDEBUG : HrJRkVkwCx9OMHYyojwvHUdMDELF2jB06 3JB 3 ret: 0
    
    Run(#45000):
    =============
    string: þ¿…wú¶sAuÆqªýUÕ£;áºÍjýL@øŽ…þÕ= è·ãÉ¢g¼äqñ>꘡MbôRù{ÕuÁ¹^ê—Ùs²@3ù/¢¦`6ƒüâIé{“óáÈí¦LýR&³,¾8¹#1ôéA¨^3Ý—#WnFbAx,ϱûV{?kwT¨2eqÈ
    bgeissl: wsAuqUjL gqMbRus36ILR81A3WnFbAxVkwT2eq ret: 0
    NDEBUG : wsAuqUjL gqMbRus36ILR81A3WnFbAxVkwT2eq ret: 0
    
    RESULTS after 50000 runs:
    bgeissl: overall: 0.100346 secs
    NDEBUG : overall: 0.096879 secs
    

    Ich mußte das hier ändern:

    //enum { bgeissl, NDEBUG };
    #define bgeissl 0
    #define NDEBUG  1
    


  • NDEBUG schrieb:

    In evaluating a[i], C converts it to *(a+i) immediately.

    einen compiler, der solche sinnlosen zwischenschritte macht, will ich gar nicht verwenden.
    🙂



  • Wieso gibt es da keine Typenprüfung, die sowas verbietet? Wenn man int i und char a[9] anlegt, daß dann tatsächlich i[a] geschrieben werden darf (hab's gerade probiert), finde ich grausam. Ich habe keine Probleme mit der internen Darstellung, aber i ist nunmal kein Pointer, weshalb krieg' ich da nichtmal eine Warning?



  • Wo ist eigentlich nun das Problem? 😕



  • Tim schrieb:

    Wo ist eigentlich nun das Problem? 😕

    Daß das total unlogisch rüberkommt.

    void problem(void)
    {
    	int *check;
    	int i = 3;	// einzelner Integer
    	char a[9];	// a ist (*char)
    
    	*check = 5;
    	a[i] = 'a'; 	// logisch, a ist Basepointer, i wird offset (*char)
    					// wir wollen ja ein array of char auflösen.
    	i[a] = 'b'; 	// unlogisch, ist i ein basepointer auf char oder gar integer?!?
    					// unlogisch ist i ein array?
    					// nein, i ist nur ein Integer!!!
    	a[*check] = 'a'; // logisch, a ist Basepointer, *check zu offset (*char)
    	*check[a] = 'b'; // Operands of + have incompatible types 'int *' and 'char *'.
    					// Type error: pointer expected - Achnee?.
    }
    

    Wo steckt die tiefere Logik dahinter, sowas wie in Zeile 10 zu erlauben? Wann wird aus welchen Vorgaben der Typ gecastet, um diese Zugriffe aufzulösen?



  • pointercrash() schrieb:

    Tim schrieb:

    Wo ist eigentlich nun das Problem? 😕

    Daß das total unlogisch rüberkommt.

    void problem(void)
    {
    	int *check;
    	int i = 3;	// einzelner Integer
    	char a[9];	// a ist (*char)
    
    	*check = 5;
    	a[i] = 'a'; 	// logisch, a ist Basepointer, i wird offset (*char)
    					// wir wollen ja ein array of char auflösen.
    	i[a] = 'b'; 	// unlogisch, ist i ein basepointer auf char oder gar integer?!?
    					// unlogisch ist i ein array?
    					// nein, i ist nur ein Integer!!!
    	a[*check] = 'a'; // logisch, a ist Basepointer, *check zu offset (*char)
    	*check[a] = 'b'; // Operands of + have incompatible types 'int *' and 'char *'.
    					// Type error: pointer expected - Achnee?.
    }
    

    google: C operator precedence...



  • NDEBUG schrieb:

    Ich mußte das hier ändern:

    //enum { bgeissl, NDEBUG };
    #define bgeissl 0
    #define NDEBUG  1
    

    Dir ist aber schon klar, dass NDEBUG ein Makro ist, welches von der Standardbibliothek verwendet wird um zwischen Debug- und Release-Version zu unterscheiden, dieses Makro von Visual Studio sogar automatisch gesetzt wird (im Releasemodus bei Standardprojekteinstellungen) und Du Dir damit höchstwahrscheinlich das Testergebnis verfälscht? 🙂



  • Guter Hinweis. Ich hab die defines geändert nach

    #define bgeissl     0
    #define peterlustig 1
    

    und die notwendigen Veränderungen vorgenommen. Es hat sich an den Ergebnissen aber nix geändert.



  • Tim schrieb:

    google: C operator precedence...

    Achja, jetzt frißt er's.

    Das war aber nicht meine Frage. Ich habe mehrfach über Arrays gelesen, daß der Name als Basispointer gilt und dann der Index dem Typen des Arrays entsprechend als Offset draufgeklatscht wird.

    Nun ist aber i immer noch kein Array, sondern ein Integer. Woher bezieht der Compiler seine Typeninformation bzw. löst die [] wirklich auf?



  • pointercrash() schrieb:

    Nun ist aber i immer noch kein Array, sondern ein Integer. Woher bezieht der Compiler seine Typeninformation bzw. löst die [] wirklich auf?

    der compiler akzeptiert einfach beide schreibweisen, array[i] und i[array]. in beiden fällen bleibt i ein 'int' und das array bleibt ein array. aus welchem grund i[array] erlaubt ist, weiss ich nicht, aber vielleicht kann uns jemand hier aufklären?
    🙂



  • Erklären kann ich es nicht, aber es funktioniert auch auf Assembler Ebene. Hier erstmal kurz ein Listing:

    #include <stdio.h>
    #include <stdlib.h>
    
    void _cdecl printit(char &c) {
        printf("%c\n", c);
    }
    
    int main(int argc, char *argv[]) {
        char a[128] = "Hello World";
    
        // a[i] access
        // c version
        printit(a[4]);
        // asm version
        _asm {
            lea     edi, a+4    // load address of a[i]
            push    edi         // push it
            call    printit     // print it
            pop     edi         // pop it
        }
    
        // i[a] access
        // c version
        printit(4[a]);
        // asm version
        _asm {
            lea     edi, 4+a    // load address of i[a]
            push    edi         // push it
            call    printit     // print it
            pop     edi         // pop it
        }
    
        system("pause");
        return 0;
    }
    

    Wie man sieht lautet der Befehl in Assembler der den Array Zugriff regelt "lea". Wenn ich mir nun also mal laienhaft vorstelle, daß jeder Array Zugriff auf folgende Art und Weise umgewandelt wird

    array[j]
    -> tokenize: token[0] = array, token[1] = j
    -> lea edi, token[0]+token[i]
    

    so erkennt man natürlich sofort daß die eigentlichen Reihenfolge der Werte total egal ist. Warum nicht stärker Typgeprüft wird, habe ich keine Ahnung.



  • NDEBUG schrieb:

    lea edi, a+4 // load address of a[i]
    lea edi, 4+a // load address of i[a]

    das ist aber der selbe asm-befehl, oder?
    🙂



  • Jep, und viellciht der Grund warum a[j] == j[a] ist.

    Edit: Achso um nochmal kurz den Bogen zu Pointern zu spannen

    *(array + j)
    -> tokenize: token[0] = '*', token[1] = array, token[2] = j
    (token 0 zeigt eine Dereferenzierung an, d.h. was folgt muß eine Adresse sein)
    -> lea edi, token[1]+token[2]
    

    Und das ist dasselbe wie bei den Arrays. Also vollkommen gleichwertig.



  • NDEBUG schrieb:

    ... Wenn ich mir nun also mal laienhaft vorstelle, daß jeder Array Zugriff auf folgende Art und Weise umgewandelt wird

    array[j]
    -> tokenize: token[0] = array, token[1] = j
    -> lea edi, token[0]+token[i]
    

    so erkennt man natürlich sofort daß die eigentlichen Reihenfolge der Werte total egal ist. Warum nicht stärker Typgeprüft wird, habe ich keine Ahnung.

    Muß wohl einen Grund haben und genau der interessiert mich eigentlich schon 😉 . Wenn man's auf dem M16C anschaut, sieht das nach selbem in Grün aus, nur daß der ASM die Addition schon aufgelöst hat:

    // i steht an offset -2 des Framebuffers
    // array[i] = 'c';
        90  0004A  EB4BE6                   	mova	-26[FB],A0	;  array 
        91  0004D  A1B4FE                   	add.w	-2[FB],A0	;  i 
        92  00050  74C663                   	mov.b	#63H,[A0]	; 'c'
    //	i[array] = 'd';
        94  00053  EB4BE6                   	mova	-26[FB],A0	;  array 
        95  00056  A1B4FE                   	add.w	-2[FB],A0	;  i 
        96  00059  74C664                   	mov.b	#64H,[A0]	; 'd'
    

    Mit dem Renesas und KPIT bis auf die Basisadresse identisch, IAR und Tasking hab' ich gar nicht erst probiert, der Compiler wirds wohl ungefähr so wie in Deiner Metasprache auflösen.
    Damit wird zumindest klar, daß an dieser Stelle keine Typenprüfung GEWÜNSCHT ist, fragt sich nur noch, warum, außer dem Wettbewerb um das unübersichtlichste Programm noch ein paar Features zu stiften. 🕶
    Also, wenn es jemand drauf anlegt, bei jedem Arrayzugriff Anker und Index zu vertauschen und dabei mit eingestreuten Pointerdereferenzierungen Verwirrung stiftet, platzt mit ab Zeile 10 der Kopf 😡 .
    Warum zum Henker wird also sowas erlaubt?



  • Der Operator [] ist halt einfach so definiert, dass a[b] gleichbedeutend mit *(a+b) ist, welches (Kommutativgesetzt) gleichbedeutend mit *(b+a) ist, welches in Folge gleichbedeutend mit b[a] ist. Was das hier speziell mit Typprüfung zu tun haben soll... keine Ahnung was du meinst. Im wesentlichen ist das Pointerarithmetik. Was ihr hier noch mit Assemblercode rumwerft verstehe ich auch nicht...



  • Tim schrieb:

    ... Was das hier speziell mit Typprüfung zu tun haben soll... keine Ahnung was du meinst.

    Weil das syntaktisch inkonsistent und verdammt nochmal i kein Array of irgendwas ist.

    Tim schrieb:

    Im wesentlichen ist das Pointerarithmetik. Was ihr hier noch mit Assemblercode rumwerft verstehe ich auch nicht...

    Wenn Du keine Erklärung für die Fragen hast, dann halte Dich einfach an Nuhr und damit den Mund (oder die vorlauten Tippelfinger).



  • pointercrash() schrieb:

    Tim schrieb:

    ... Was das hier speziell mit Typprüfung zu tun haben soll... keine Ahnung was du meinst.

    Weil das syntaktisch inkonsistent und verdammt nochmal i kein Array of irgendwas ist.

    Es ist eine Definition und diese ist konsistent. Wenn dir die Definition nicht gefällt und/oder sie nicht verstehst, kannst du wie so viele andere einen Rant auf youtube stellen.

    Tim schrieb:

    Im wesentlichen ist das Pointerarithmetik. Was ihr hier noch mit Assemblercode rumwerft verstehe ich auch nicht...

    Wenn Du keine Erklärung für die Fragen hast, dann halte Dich einfach an Nuhr und damit den Mund (oder die vorlauten Tippelfinger).[/quote]
    Sorry, ich werde mich in Zukunft zurückhalten deine Wissenslücken zu stopfen. 😉



  • Tim schrieb:

    Der Operator [] ist halt einfach so definiert, dass a[b] gleichbedeutend mit *(a+b) ist, welches (Kommutativgesetzt) gleichbedeutend mit *(b+a) ist, welches in Folge gleichbedeutend mit b[a] ist.

    bekannte tatsachen vorzubeten hilft uns nicht weiter. wir wollen doch wissen, warum man für array[i] auch i[array], aber nicht [i]array hinschreiben kann. ist es ein abfallprodukt irgendwelcher parsing-techniken, ein bug in der syntaxdefinition, oder steckt tatsächlich ein sinn dahinter? dass array[i] das gleiche ist wie *(array+i) erklärt überhaupt nichts. wo sind eigentlich diese ganzen freaks, die hier immer den c-standard vorwärts und rückwärts aufsagen? das muss doch irgendwer wissen.
    🙂



  • Also, bei den untersuchten Compilern (KPIT/Renesas) werden auch außerhalb des Codeblocks definierte statics als Offset des Framebuffers gehandhabt, was auf eine generelle Pointeraddition hinweist, eine MMU gibt es hier nicht.
    Also löst der Compiler a[b] = irgendwas; wohl so nach dem Motto auf "mir brauchen an Pointer, den Typ drauf, machen intern einen sizeof(*typ) und mal dem anderen Kameraden (probeweise kommutativ) und das wird's wohl sein.
    Ich muß es ja nicht mögen, aber verstehen wollte ich's schon. 😉


Anmelden zum Antworten