char pointer aus C

12/12/2011 - 16:15 von Thomas Wildgruber | Report spam
Hi Group,

Anfàngerfrage: Ich habe in einem C Programm einen char Pointer deklariert
und initialisiert und versuche nun das Verhalten dieses Zeigers im
Disassembly nachzuvollziehen.

Der C Code:
snip
#include <stdio.h>

int main() {
char carray[3] = {'a', 'b', 'c'};
char *c = "abc";
int i;
int k;

for(i = 0; i < 3; i++) {
printf("char array carray[%d] points to %c on address %p", i,
carray[i], &carray[i]);
}

for(k = 0; k < 3; k++) {
printf("char pointer *c[%d] points to %c on address %p", k, c[k],
&c[k]);
}
return 0;
}
snap

Gibt mir erwartungsgemàß folgendes zurück:

snip
char array carray[0] points to a on address 0xbffffca1
char array carray[1] points to b on address 0xbffffca2
char array carray[2] points to c on address 0xbffffca3
char pointer *c[0] points to a on address 0x8048540
char pointer *c[1] points to b on address 0x8048541
char pointer *c[2] points to c on address 0x8048542
snap

Das Disassembly (ohne for-Schleifen):

snip
0x080483cd <main+9>: mov BYTE PTR [esp+0x11],0x61
0x080483d2 <main+14>: mov BYTE PTR [esp+0x12],0x62
0x080483d7 <main+19>: mov BYTE PTR [esp+0x13],0x63
0x080483dc <main+24>: mov DWORD PTR [esp+0x14],0x8048540
snap

Mein Verstàndnisproblem ist die Zeile <main+24>, wo die Adresse 0x8048540
des char-Pointers *c in den Stack Pointer (esp) kopiert wird. Aus der oz
Ausgabe des Programms schließe ich, dass auch bei einem char-Pointer der
Zeiger nur auf die Adresse des ersten Elements (des daraus resultierenden
Arrays) zeigt, denn die nàchsten Adressen sind jeweils um 1 erhöht
(0x8048540, 0x8048541, 0x8048542). Um eventuelle Wahrnehmungsfehler
meinserseits auszuschließen habe ich das ganze im Debugger überprüft:

snip
(gdb) x/c 0x8048540
0x8048540: 97 'a'
(gdb) x/c 0x8048541
0x8048541: 98 'b'
(gdb) x/c 0x8048542
0x8048542: 99 'c'
snap

Mein Verstàndnisproblem kommt dann, wenn ich im Debugger nicht ein Zeichen
in einer Adresse untersuche (x/c) sondern einen String (x/s):

snip
(gdb) x/s 0x8048540
0x8048540: "abc"
(gdb) x/s 0x8048541
0x8048541: "bc"
(gdb) x/s 0x8048542
0x8048542: "c"
snap

Wieso sieht man in der Adresse 0x8048540 plötzlich den ganzen String? Nach
dem ganzen Zenober von oben würde ich hier nur ein a erwarten.

Andererseits jedoch bin ich bei der ersten Analyse des Disassembly schon
davon ausgegangen, dass in der Adresse 0x8048540 schon der ganze String
stehen muss, denn es folgt keine weitere Maschinencode-Anweisung welche
explizit die nàchsten Zeichen des Strings bzw. die nàchsten Adressen
anspricht. Jetzt bin ich ein wenig verwirrt, kann jemand für Aufklàrung
sorgen?

Wenn es von Interesse sein sollte, hier noch mal das gesamte Disassembly:

snip
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: and esp,0xfffffff0
0x080483ca <main+6>: sub esp,0x20
0x080483cd <main+9>: mov BYTE PTR [esp+0x11],0x61
0x080483d2 <main+14>: mov BYTE PTR [esp+0x12],0x62
0x080483d7 <main+19>: mov BYTE PTR [esp+0x13],0x63
0x080483dc <main+24>: mov DWORD PTR [esp+0x14],0x8048540
0x080483e4 <main+32>: mov DWORD PTR [esp+0x18],0x0
0x080483ec <main+40>: jmp 0x8048426 <main+98>
0x080483ee <main+42>: mov edx,DWORD PTR [esp+0x18]
0x080483f2 <main+46>: lea eax,[esp+0x11]
0x080483f6 <main+50>: add eax,edx
0x080483f8 <main+52>: mov edx,DWORD PTR [esp+0x18]
0x080483fc <main+56>: movzx edx,BYTE PTR [esp+edx*1+0x11]
0x08048401 <main+61>: movsx ecx,dl
0x08048404 <main+64>: mov edx,0x8048544
0x08048409 <main+69>: mov DWORD PTR [esp+0xc],eax
0x0804840d <main+73>: mov DWORD PTR [esp+0x8],ecx
0x08048411 <main+77>: mov eax,DWORD PTR [esp+0x18]
0x08048415 <main+81>: mov DWORD PTR [esp+0x4],eax
0x08048419 <main+85>: mov DWORD PTR [esp],edx
0x0804841c <main+88>: call 0x80482fc <printf@plt>
0x08048421 <main+93>: add DWORD PTR [esp+0x18],0x1
0x08048426 <main+98>: cmp DWORD PTR [esp+0x18],0x2
0x0804842b <main+103>: jle 0x80483ee <main+42>
0x0804842d <main+105>: mov DWORD PTR [esp+0x1c],0x0
0x08048435 <main+113>: jmp 0x8048471 <main+173>
0x08048437 <main+115>: mov eax,DWORD PTR [esp+0x1c]
0x0804843b <main+119>: mov ecx,eax
0x0804843d <main+121>: add ecx,DWORD PTR [esp+0x14]
0x08048441 <main+125>: mov eax,DWORD PTR [esp+0x1c]
0x08048445 <main+129>: add eax,DWORD PTR [esp+0x14]
0x08048449 <main+133>: movzx eax,BYTE PTR [eax]
0x0804844c <main+136>: movsx edx,al
0x0804844f <main+139>: mov eax,0x8048578
0x08048454 <main+144>: mov DWORD PTR [esp+0xc],ecx
0x08048458 <main+148>: mov DWORD PTR [esp+0x8],edx
0x0804845c <main+152>: mov edx,DWORD PTR [esp+0x1c]
0x08048460 <main+156>: mov DWORD PTR [esp+0x4],edx
0x08048464 <main+160>: mov DWORD PTR [esp],eax
0x08048467 <main+163>: call 0x80482fc <printf@plt>
0x0804846c <main+168>: add DWORD PTR [esp+0x1c],0x1
0x08048471 <main+173>: cmp DWORD PTR [esp+0x1c],0x2
Type <return> to continue, or q <return> to quit
0x08048476 <main+178>: jle 0x8048437 <main+115>
0x08048478 <main+180>: mov eax,0x0
0x0804847d <main+185>: leave
0x0804847e <main+186>: ret
End of assembler dump.
snap

Danke fürs Lesen & Bye Tom
"Der Retter der Welt ist ein Pinguin und Linus Torvalds ist sein Prophet "
 

Lesen sie die antworten

#1 Heiko Nocon
12/12/2011 - 18:21 | Warnen spam
Thomas Wildgruber wrote:

Mein Verstàndnisproblem ist die Zeile <main+24>, wo die Adresse 0x8048540
des char-Pointers *c in den Stack Pointer (esp) kopiert wird.



Nein, wird sie nicht. Du hast auf dem Stackframe eine Zeiger_variable_
und DIE wird mit der Anfangsadresse des Puffer initialisiert. Das
entspricht dieser Zeile in C:

char *c = "abc";

Aus der oz
Ausgabe des Programms schließe ich, dass auch bei einem char-Pointer der
Zeiger nur auf die Adresse des ersten Elements (des daraus resultierenden
Arrays) zeigt



Nein. Ein char-Zeiger _enthàlt_ _irgendeine_ Adresse. Erst durch die
Initialisierung wird festgelegt, daß es die Adresse des ersten Elementes
des "abc"-Puffers ist.

Mein Verstàndnisproblem kommt dann, wenn ich im Debugger nicht ein Zeichen
in einer Adresse untersuche (x/c) sondern einen String (x/s):

snip
(gdb) x/s 0x8048540
0x8048540: "abc"
(gdb) x/s 0x8048541
0x8048541: "bc"
(gdb) x/s 0x8048542
0x8048542: "c"
snap

Wieso sieht man in der Adresse 0x8048540 plötzlich den ganzen String?



Weil der Debugger den Speicherbereich als nullterminierte Zeichenkette
betrachtet und wohl (nicht ganz zufàllig) nach dem "abc" eine Null im
Speicher liegt. Sonst wàre der angezeigte String noch lànger. Würde sich
aber bei aufsteigender Anfangsadresse aber natürlich trotzdem jeweils um
das erste Zeichen verkürzen.

Wenn du nicht alles bis zur nàchsten Null (oder bis zur Làngenbegrenzung
der Debuggerausgabe) sehen willst, mußt du derefenzieren, dem Debugger
also sagen, daß dich nicht "Speicher ab Adresse interpretiert als Folge
von chars" interessiert, sondern nur "einzelnes char auf Adresse". An
der Adresse selber oder dem Inhalt des Speichers àndert sich dadurch
_absolut nix_. Der Speicherinhalt wird nur anders interpretiert. Das ist
also eine reine Anzeigegeschichte.

Keine Ahnung, wie man das dem gdb klarmacht, beim Delphi-Debugger müßte
ich einfach nur ein Caret-Zeichen an den Namen der Zeigervariablen
anhàngen, deren (indirekten) Inhalt ich mir angucken will. Dann weiß
der, daß mich nur das aktuell adressierte Element interessiert.

Ähnliche fragen