Discussion:
char*-RAM auf Struktur-Array casten: Absturz bei Zugriff
(zu alt für eine Antwort)
ha
2015-06-03 23:46:36 UTC
Permalink
Raw Message
Hallo

Ich sehe wohl den Wald vor Bäumen nicht.

Ich möchte auf Speicher (char*) per Casting als ein
Array von Strukturen zugreifen. Aber es gibt sofort
einen Absturz.

Hier ein simples Beispiel. (Um nicht vom eigentl.
Problem in Form von Nebendiskussionen zur Form
abzulenken, habe ich die Sache als kleine
Funktion geschrieben ;-) )


void test(void)
{
struct testS
{
int x;
};

char *P;
struct testS* sP;


if (!(P = (char*)malloc(sizeof(struct testS) * 10)))
{
return;
}

sP = (struct testS*)P[0];

sP->x = 1; // Hier knallt es

// Natürlich geht dann auch das hier nicht: (struct testS*)P[0]->x =
1;

free(P);
}


Was mache ich falsch? Oder liegt es am Compiler?
Ich erinnere mich, das man beim Watcom das
Struktur-Alignment einstellen konnte.

Ich arbeite unter Win7 mit dem VSE2013.
Rüdiger Ranft
2015-06-04 06:30:14 UTC
Permalink
Raw Message
Post by ha
Hallo
Ich sehe wohl den Wald vor Bäumen nicht.
Ich möchte auf Speicher (char*) per Casting als ein
Array von Strukturen zugreifen. Aber es gibt sofort
einen Absturz.
Hier ein simples Beispiel. (Um nicht vom eigentl.
Problem in Form von Nebendiskussionen zur Form
abzulenken, habe ich die Sache als kleine
Funktion geschrieben ;-) )
void test(void)
{
struct testS
{
int x;
};
char *P;
struct testS* sP;
if (!(P = (char*)malloc(sizeof(struct testS) * 10)))
{
return;
}
sP = (struct testS*)P[0];
^^^
Hier greifst Du auf das erste (nicht initialisierte) Element von P zu,
und wandelst es in einen Zeiger um. Was Du eigentlich schreiben wolltest war
sP = (struct testS*)P; /* oder (struct testS*)&P[0]; */

BTW: Wenn Du ein array von testS anlegen willst, kannst Du auch calloc
verwenden:
sP = calloc(10, sizeof(*sP));

Das schützt dann auch vor Problemen wie in [1] beschrieben, hat aber den
Nachteil, dass bei vielen Umgebungen zusätzlicher Aufwand für das
initialisieren des Speichers notwendig ist.

Bye
Rudi.

[1] https://drj11.wordpress.com/2008/06/04/calloc-when-multiply-overflows/
Heinz Saathoff
2015-06-04 06:33:52 UTC
Permalink
Raw Message
Moin,
Post by ha
Ich sehe wohl den Wald vor Bäumen nicht.
Ich möchte auf Speicher (char*) per Casting als ein
Array von Strukturen zugreifen. Aber es gibt sofort
einen Absturz.
void test(void)
{
struct testS
{
int x;
};
char *P;
struct testS* sP;
if (!(P = (char*)malloc(sizeof(struct testS) * 10)))
{
return;
}
sP = (struct testS*)P[0];
^^^^^

Der cast ist falsch. Du willst P casten, aber nicht das, worauf P
zeigt. P[0] dereferenziert P, ist also identisch mit *P

Also einfach
sP = (struct testS*)P;
schreiben. Dann klappt's auch.


- Heinz
ha
2015-06-04 11:02:23 UTC
Permalink
Raw Message
Danke für die Antworten. Wenn man erstmal
den Überblick verliert, dann hält sich das
hartnäckig :-)

Ich greife jetzt nach diesem Muster auf die
Struktur zu:

((struct testS* ) P)[0].x = 123;
Heinz Saathoff
2015-06-05 06:25:54 UTC
Permalink
Raw Message
Post by ha
Ich greife jetzt nach diesem Muster auf die
((struct testS* ) P)[0].x = 123;
Bleibt die Frage, warum du P überhaupt als überhaupt als char*
anlegst, wenn Du doch ein struct testS* haben möchtest?
Du kannst doch gleich das Ergebnis von malloc einem
struct testS* zuweisen und ersparst dir dann alle weiteren
casts.


- Heinz
Georg Bauhaus
2015-06-05 10:51:42 UTC
Permalink
Raw Message
Post by Heinz Saathoff
Post by ha
Ich greife jetzt nach diesem Muster auf die
((struct testS* ) P)[0].x = 123;
Bleibt die Frage, warum du P überhaupt als überhaupt als char*
anlegst, wenn Du doch ein struct testS* haben möchtest?
Du kannst doch gleich das Ergebnis von malloc einem
struct testS* zuweisen und ersparst dir dann alle weiteren
casts.
Für einen verallgemeinerten Zugriff kann "neuerdings" (seit
einigen Jahrzehnten) auch void* der Vorzug vor char* gegeben
werden; für letzteren gibt es definierte Konversionsregeln
in der C-Norm.
Georg Bauhaus
2015-06-05 12:21:49 UTC
Permalink
Raw Message
Post by Georg Bauhaus
Für einen verallgemeinerten Zugriff kann "neuerdings" (seit
einigen Jahrzehnten) auch void* der Vorzug vor char* gegeben
werden; für
s/letzteren/voids*/
Post by Georg Bauhaus
gibt es definierte Konversionsregeln
in der C-Norm.
ha
2015-06-05 15:51:54 UTC
Permalink
Raw Message
Post by Heinz Saathoff
Bleibt die Frage, warum du P überhaupt als überhaupt als char*
anlegst, wenn Du doch ein struct testS* haben möchtest?
Du kannst doch gleich das Ergebnis von malloc einem
struct testS* zuweisen und ersparst dir dann alle weiteren
casts.
Weil ich eine Datei ins RAM hole und auf versch. Weise
darauf zugreifen muss. Der Datenbereich besteht aus
mehreren Sektionen. U.a. auch aus einem Strukturarray.
Stefan Ram
2015-06-04 20:28:49 UTC
Permalink
Raw Message
Post by ha
Hier ein simples Beispiel. (Um nicht vom eigentl.
Problem in Form von Nebendiskussionen zur Form
abzulenken, habe ich die Sache als kleine
Funktion geschrieben ;-) )
Das wird Dir nicht helfen, denn jetzt kommen sofort
Schlaumeier, die sagen, daß »test()« keine Wirkung
hat, also einfach zu »test(){}« vereinfacht werden
kann.

|struct testS { int x; };
|if (!(P = (char*)malloc(sizeof(struct testS) * 10)))
| return;
|sP = (struct testS*)P[0];

Ich verwende folgenden Stil:

include <stdlib.h>

int main()
{ struct P { int n; }( *p )[ 10 ]= malloc( 10 * sizeof * p );
if( p ){ ( *p )[ 0 ].n = 0; ( *p )[ 9 ].n = 9; free( p ); }}

Allerdings sollte man so etwas noch mal mit valgrind oder
ähnlichen Programmen testen.
ha
2015-06-04 21:38:36 UTC
Permalink
Raw Message
Post by Stefan Ram
include <stdlib.h>
int main()
{ struct P { int n; }( *p )[ 10 ]= malloc( 10 * sizeof * p );
if( p ){ ( *p )[ 0 ].n = 0; ( *p )[ 9 ].n = 9; free( p ); }}
Noch etwas mehr und du kannst hier mitmachen:

http://www.ioccc.org/

Sorry, konnte nicht widerstehen ;-)
Stefan Ram
2015-06-04 21:47:22 UTC
Permalink
Raw Message
Post by Stefan Ram
include <stdlib.h>
int main()
{ struct P { int n; }( *p )[ 10 ]= malloc( 10 * sizeof * p );
if( p ){ ( *p )[ 0 ].n = 0; ( *p )[ 9 ].n = 9; free( p ); }}
Ich muß meinen Beitrag korrigieren:

#include <stdlib.h>

int main()
{ struct { int n; }( *p )[ 10 ]= malloc( 10 * sizeof( *p )[ 0 ]);
if( p ){ ( *p )[ 0 ].n = 0;( *p )[ 9 ].n = 9; free( p ); }}

Zum einen wurde das »sizeof« fälschlicherweise auf »* p« angewendet.
Zum anderen war das (große )»P« überflüssig.
Juergen Ilse
2015-06-09 00:18:35 UTC
Permalink
Raw Message
Hallo,
Post by ha
Ich möchte auf Speicher (char*) per Casting als ein
Array von Strukturen zugreifen. Aber es gibt sofort
einen Absturz.
Hier ein simples Beispiel. (Um nicht vom eigentl.
Problem in Form von Nebendiskussionen zur Form
abzulenken, habe ich die Sache als kleine
Funktion geschrieben ;-) )
void test(void)
{
struct testS
{
int x;
};
char *P;
struct testS* sP;
if (!(P = (char*)malloc(sizeof(struct testS) * 10)))
{
return;
}
sP = (struct testS*)P[0];
sP = (struct testS*)&(P[0]);
Post by ha
sP->x = 1; // Hier knallt es
Genau. Weil du den Wert des ersten char deines arrays zu einem Pointer
castest (was nicht sonderlich sinnvoll ist) und dann versuchst, diesen
Pointer zu dereferenzieren ... --> BUMM!
Post by ha
Was mache ich falsch?
Siehe oben.
Post by ha
Oder liegt es am Compiler?
Am Compiler liegt es hoechstens, dass du beim uebersetzen dieses Codes
keine Warnung bekommst (oder hast du eine Warnung erhalten aber
ignoriert?).
Post by ha
Ich erinnere mich, das man beim Watcom das
Struktur-Alignment einstellen konnte.
Das ist (zumindest hier) nicht das Problem.
Du hast das mit den Pointern und den arrays IMHO nicht verstanden ...
Siehe http://www.dclc-faq.de/kap2.htm

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Heinz Saathoff
2015-06-09 06:19:54 UTC
Permalink
Raw Message
Moin,
Post by Juergen Ilse
Post by ha
Oder liegt es am Compiler?
Am Compiler liegt es hoechstens, dass du beim uebersetzen dieses Codes
keine Warnung bekommst (oder hast du eine Warnung erhalten aber
ignoriert?).
Ist ein cast nicht eine Zusage an den Compiler, dass der Programmierer
weiss, was er tut und deshalb keine Warnung geben muß?


- Heinz
Juergen Ilse
2015-06-09 11:00:17 UTC
Permalink
Raw Message
Hallo,
Post by Heinz Saathoff
Post by Juergen Ilse
Post by ha
Oder liegt es am Compiler?
Am Compiler liegt es hoechstens, dass du beim uebersetzen dieses Codes
keine Warnung bekommst (oder hast du eine Warnung erhalten aber
ignoriert?).
Ist ein cast nicht eine Zusage an den Compiler, dass der Programmierer
weiss, was er tut und deshalb keine Warnung geben muß?
Viele Compiler warnen aber dennoch, wenn man ein char (nicht etwas ein char*)
zu einem (beliebigen) Pointer-Typ zu konvertieren versucht ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
ha
2015-06-09 15:15:03 UTC
Permalink
Raw Message
Post by Juergen Ilse
Du hast das mit den Pointern und den arrays IMHO nicht verstanden ...
Hm, eigentlich habe ich das nicht schlechter verstanden, als du ;-)

Ich hatte mich verzettelt und das war eine Situation, in der man
grübelt, ob "Otto" richtig geschrieben ist. Am nächsten Tag hatte ich
mir vor die Stirn gehauen und sah dann aber, das hier bereits
geantwortet wurde. (Vielleicht entschuldigt die Uhrzeit meine Eselei
ein wenig, als ich die Frage hier stellte ;-) )
Post by Juergen Ilse
Siehe http://www.dclc-faq.de/kap2.htm
Danke für den Link. Das ist schön anschaulich zusammengefasst.
Bernd Nawothnig
2015-06-11 09:16:36 UTC
Permalink
Raw Message
Post by Juergen Ilse
Post by ha
sP = (struct testS*)P[0];
sP = (struct testS*)&(P[0]);
sP = (struct testS*)P;

Tut dasselbe.



Bernd
--
no time toulouse
Loading...