Zeiger auf Literal
-
Meine Frage wäre wie sollte C es denn intern ohne Zeigerzugriffe machen?
-
volkard schrieb:
~fricky schrieb:
NDEBUG schrieb:
Array Zugriffe werden intern von C in Pointer Zugriffe umgewandelt. So wird aus array[j] -> *(array + j).
nö, warum sollte C sowas tun?
warum nicht.
NDEBUGs beschreibung erklärt mir endlich mal, warum man immer, wo array[j] geht, auch j[array] geht. weil *(array + j) == *(j + array). weil array + j == j + array.
welche tatsachen sprechen für dein "nö, warum sollte C sowas tun?"?weil eine umwandlung ein unnötiger umweg wäre. ein C-compiler versteht alle diese ausdrücke und macht exakt das gleiche daraus (möglicherweise schon so, dass er intern eine eine funktion aufruft: 'indirekte_addressierung_mit_offset(a,b)'). aber davon sieht man im output nix mehr.
Meine Frage wäre wie sollte C es denn intern ohne Zeigerzugriffe machen?
unterschiedlich. bei 'nem konstanten indexwert könnte z.b. der compiler schon die absolute adresse berechnen. aber was am ende rauskommt, ist ja von der ziel-CPU abhängig. wenn die nichts zeiger-änliches kennt, dann müssen C-zeiger, arrays, etc. irgendwie simuliert werden.
-
~fricky da haste aber deine Hausaufgaben nicht gemacht:
In evaluating a[i], C converts it to *(a+i) immediately; the two forms are equivalent.
"The C Programming Language - Ansi C - 2nd Edition", Brian W. Kernighan, Dennis M. Ritchie (Seite 89)
-
Ich hab den Test mal laufen lassen. Hier der Testcode:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <assert.h> #include <windows.h> // timer static _int64 ticks_per_sec; static _int64 timer_start; static float secs_per_tick; void timer_init() { printf("Initializing timer ... "); if(!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_sec)) { printf("Error: No perfomance counter available.\n"); exit(1); } else { QueryPerformanceCounter((LARGE_INTEGER *)&timer_start); secs_per_tick = ((double)1.0)/((double)ticks_per_sec); } printf("OK\n"); } float query_timer() { _int64 time; QueryPerformanceCounter((LARGE_INTEGER *)&time); return(((float)(time - timer_start)) * secs_per_tick); } // rand stuff void rand_init(void) { printf("Initializing random number generator ... "); srand((int)query_timer()); printf("OK\n"); } int rand_get(int min, int max) { return rand() % (max - min + 1) + min; } // test stuff #define MAX_STRINGS 50000 #define MAX_STRINGLEN 128 static char teststrings[MAX_STRINGS][MAX_STRINGLEN]; static char from_else[MAX_STRINGLEN] = "String was not copied."; // testfunction bgeissl int copystring_bgeissl(char *source, char *target,int start, int length, char *ifempty){ int i = 0; int j = 0; int len = length; char *oldtarget; oldtarget = target; source += start; while (length-- && *source) { if ((*source > 64 && *source < 91) || (*source > 96 && *source < 123) || (*source > 47 && *source < 58)){; *target = *source; target++; i = 1; }if(*source == 32){ *target = *source; target++; } source++; } *target = 0; //Wenn man Vergleichs- und Zuweisungsoperatoren verwechselt :-)... //"if (i = 0)" war natürlich falsch. if (i == 0) { //Hier musste "target" aus "oldtarget" gelesen werden, weil //sich durch "target++" wirklich auch "&target[0]" geändert hat! - Wie krass! //(siehe Erklärung am Ende des letzten Post) target = oldtarget; *target = 0; while(*ifempty && len--){ *target = *ifempty; target++; ifempty++; } *target = 0; return 1; } return 0; } // testfunction NDEBUG // removed dependency on ctype.h and string.h int copystring_NDEBUG(const char from[], char to[], int start, int length, const char from_else[]) { int i, j; for(i = start, j = 0; j < length && from[i] != '\0'; i++) { if((from[i] >= '0' && from[i] <= '9') || (from[i] >= 'A' && from[i] <= 'Z') || (from[i] >= 'a' && from[i] <= 'z') || from[i] == ' ') to[j++] = from[i]; } if(j > 0) { to[j] = '\0'; return 0; } while(*to++ = *from_else++); return 1; } enum { bgeissl, NDEBUG }; int main(int argc, char *argv[]) { char to[2][MAX_STRINGLEN]; int ret[2]; int i, j, str_begin, str_end, str_len; float time_start, time_end, time[2] = {0.0, 0.0}; // setup stuff timer_init(); rand_init(); // init teststrings array with random strings // only contain printable chars from 28 - 254 printf("Initializing test array ... "); for(i = 0; i < MAX_STRINGS; i++) { for(j = 0; j < MAX_STRINGLEN; j++) { teststrings[i][j] = (char)rand_get(28, 254); } teststrings[i][MAX_STRINGLEN - 1] = '\0'; } printf("OK"); for(i = 0; i < MAX_STRINGS; i++) { // make the start and end random str_begin = rand_get(0, (MAX_STRINGLEN / 2) - 1); str_end = rand_get((MAX_STRINGLEN / 2) + 1, MAX_STRINGLEN); str_len = str_end - str_begin; // run bgeissl time_start = query_timer(); ret[bgeissl] = copystring_bgeissl(teststrings[i], to[bgeissl], 0, MAX_STRINGLEN, from_else); time_end = query_timer(); time[bgeissl] += time_end - time_start; // run NDEBUG time_start = query_timer(); ret[NDEBUG] = copystring_NDEBUG(teststrings[i], to[NDEBUG], 0, MAX_STRINGLEN, from_else); time_end = query_timer(); time[NDEBUG] += time_end - time_start; // assert total equality assert(!strcmp(to[bgeissl], to[NDEBUG])); assert(ret[bgeissl] == ret[NDEBUG]); // every now and then print some reference texts if(i % (MAX_STRINGS/10) == 0) { printf("\nRun(#%5d):\n", i); printf("=============\n"); printf("string: %s\n", teststrings[i]); printf("bgeissl: %s ret: %d\n", to[bgeissl], ret[bgeissl]); printf("NDEBUG : %s ret: %d\n", to[NDEBUG], ret[NDEBUG]); } } printf("\n\nRESULTS after %d runs:\n", MAX_STRINGS); printf("bgeissl: overall: %f secs\n", time[bgeissl]); printf("NDEBUG : overall: %f secs\n\n\n", time[NDEBUG]); system("pause"); return 0; }
Und hier ein Testlauf:
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èá|!‡ôékrê·åÜä³”°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.È÷±´“fEn{’£½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¨2eqÈ bgeissl: wsAuqUjL gqMbRus36ILR81A3WnFbAxVkwT2eq ret: 0 NDEBUG : wsAuqUjL gqMbRus36ILR81A3WnFbAxVkwT2eq ret: 0 RESULTS after 50000 runs: bgeissl: overall: 0.130833 secs NDEBUG : overall: 0.139831 secs
EDIT: wenn ich den Start des String randomize und die Länge die kopiert werden soll auch. Liefern unsere Funktionen nicht den gleichen String zurück! Assert schlägt hier fehl!
-
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èá|!‡ôékrê·åÜä³”°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.È÷±´“fEn{’£½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¨2eqÈ 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...