Forum: Mikrocontroller und Digitale Elektronik Verschachtelte Pointer - C Frage


von Flo (Gast)


Lesenswert?

Hallo Leute,

könnte ihr mir eventuell bei folgender Codezeile weiterhelfen?
1
(*((unsigned long*)&netmask[0]))       = (*((unsigned long*)&cache.netmask[0]));

Netmask ist vom Typ:
1
unsigned char netmask[4];

Mir ist soweit klar, dass er sich die Adresse vom ersten Char holt und 
dies in ein Long packt, also alle 4 Chars im Long hat. Was aber macht 
der erste * bei den Anweisungen?

Danke für die Rückmeldungen :)

mfg Flo

von foofoo (Gast)


Lesenswert?

das dereferenziert den Pointer (der es nach dem casten noch ist), um 
einen Wertevergleich und nicht einen Adressvergleich zu machen ...

von Udo S. (urschmitt)


Lesenswert?

foofoo schrieb:
> um einen Wertevergleich
ein einfaches '=' ist aber eine Zuweisung, kein Vergleich.

von Udo S. (urschmitt)


Lesenswert?

Im Prinzip (wenn meine eingerosteten C Kenntnisse jetzt nicht purzelbaum 
schlagen) kopiert er doch einfach 4 Bytes (sizeof(long)) von 
cache.netmask nach netmask.
Das funktioniert aber nur wennd ie Bytes gepackt sind und der Prozessor 
byteweise auf den Speicher zugreifen kann.
Typisches Beispiel C zu missbrauchen um 'schneller' zu sein oderf 
weniger Codezeilen zu haben.
Eine Schleife über die 4 Bytes wären besser lesbar und würden auf allen 
Systemen funktionieren.

von foofoo (Gast)


Lesenswert?

oh, übersehen. Dann natürlich eine Wertezuweisung und keine 
Addresszuweisung ...

von Udo S. (urschmitt)


Lesenswert?

Udo Schmitt schrieb:
> ine Schleife über die 4 Bytes wären besser lesbar und würden auf allen
> Systemen funktionieren.
Und wenn man dann die 4 in eine Konstante packt dann funktionierts sogar 
noch wenn die Arraygröße mal geändert wird.

von Flo (Gast)


Lesenswert?

Danke für die Antworten :)

Aber wenn ich eine Long Variable einer anderen Long Variable zuordne, 
dann ist das doch eine Wertzuweisung, weil
1
(unsigned long*)&cache.netmask[0]
ist dann doch ein Long mit den entsprechenden Werten, der auch einem 
anderen Long zugewiesen werden können müsste?
Oder hab ich da jetzt ein Denkfehler?

Würde folgendes nicht funktionieren:
1
unsigned long test = (unsigned long*)&cache.netmask[0];
so müsste ich doch in meiner test Variable die Netmask quasi am "Stück" 
stehen haben?

lg Flo

von Karl H. (kbuchegg)


Lesenswert?

Flo schrieb:
> Danke für die Antworten :)
>
> Aber wenn ich eine Long Variable einer anderen Long Variable zuordne,
> dann ist das doch eine Wertzuweisung, weil
>
1
(unsigned long*)&cache.netmask[0]
> ist dann doch ein Long mit den entsprechenden Werten, der auch einem
> anderen Long zugewiesen werden können müsste?
> Oder hab ich da jetzt ein Denkfehler?

Der ganze Ausdruck ergibt aber keinen Long.
Der Ausdruck ergibt einen Pointer auf einen Long.

> Würde folgendes nicht funktionieren:
>
1
unsigned long test = (unsigned long*)&cache.netmask[0];

Links steht ein Long, rechts steht ein Pointer
-> kann also nicht funktionieren

Du musst schon ein bischen auch auf die Datentypen achten!
Vor allen Dingen auf die Sterne.

von 123 (Gast)


Lesenswert?

Sieht irgendwie verdammt kompliziert aus

also 4 byte in ein array schieben,
sich vom ersten byte den Pointer holen,
diesen dann in einen Pointer von einem Long casten,
Um desen dann wieder zu derefenrzieren um an den wert des Longs zu 
kommen.

kann man so machen, gibt aber sicher schönere versionen davon.

Weiso ist netmask nicht gleich ein Long?
Ginge das ggf über ein union?
Ist das nicht ggf sogar gefährlich da nicht portabel? (big / litle 
endion)

von foofoo (Gast)


Lesenswert?

das ist eine gern gemachte "Optimierung", wenn z.B. alter 8Bit C-Code 
auf eine 32Bit Maschine portiert wird. Dann kann man eben 4Bytes "on the 
fly" mit einem Befehl kopieren ...

von C-Lerner (Gast)


Lesenswert?

Geht das?

unsigned long test = (unsigned long)((unsigned long*)&cache.netmask[0]);

von Udo S. (urschmitt)


Lesenswert?

123 schrieb:
> Weiso ist netmask nicht gleich ein Long?
Weil da sowas wie 175.100.101.75 drinsteht.

123 schrieb:
> Ist das nicht ggf sogar gefährlich da nicht portabel? (big / litle
> endion)
Big/little endian wäre hier nicht das Problem, da du bei der Zuweisung 
beide Variablen auf der bleichen Maschine hast. Aber manch Prozessoren 
können auf einzelne Bytes nicht auf ungeraden Adressen zugreifen und da 
krachts dann.
Im Netz benutzt man übrigens die sogenannte "net byte order" das 
entspricht soviel ich weiss dem big endian

Union wäre möglich aber nur wennd as Array gepackt ist.
Ist wie gesagt unnötig, for Schleife tuts auch.

von Udo S. (urschmitt)


Lesenswert?

C-Lerner schrieb:
> Geht das?
>
> unsigned long test = (unsigned long)((unsigned long*)&cache.netmask[0]);

Geht auf einer 32 Bit Maschine, aber du castest einen Pointer in einen 
Long Wert. Du dereferenzierst ihn nicht.
Was willst du damit erreichen?

Zusatz
richtiger wäre eher
unsigned long test = *((unsigned long*)&cache.netmask[0]);
unsigned long *test = (unsigned long*)&cache.netmask[0];

von Flo (Gast)


Lesenswert?

ahso, der * hinterm Long macht ja quasi einen Long Pointer, der dann als 
Startadresse den vom Array[0] bekommt und dereferenziert gibt er eben 
Long, also die 4 Byte zurück.

Jetzt wirds langsam heller, danke ;)

lg Flo

von C-Lerner (Gast)


Lesenswert?

Hallo

ok, sowas in dieser Richting meinte ich. Vielen Dank!

>Zusatz
richtiger wäre eher
unsigned long test = *((unsigned long*)&cache.netmask[0]);
unsigned long *test = (unsigned long*)&cache.netmask[0];

Udo Schmitt schrieb:
> Zusatz
> richtiger wäre eher
> unsigned long test = *((unsigned long*)&cache.netmask[0]);
> unsigned long *test = (unsigned long*)&cache.netmask[0];
>

Ich muß da mal damit spielen......und im Debugger anschauen was 
geschieht...

von Udo S. (urschmitt)


Lesenswert?

C-Lerner schrieb:
> Ich muß da mal damit spielen......und im Debugger anschauen was
> geschieht...

Du musst nur den Unterschied verstehen lernen zwischen einem Wert, der 
irgendwo im Speicher steht und dem Zeiger (Pointer) der auf den 
Speicherort zeigt.

long test; // test ist ein long wert, der im Speicher 4 Byte belegt.
long *ptest = &test;  // ptest ist ein zeiger der auf test zeigt.

*ptest = 123; // ich schreibe den Wert 123 in die Stelle auf die der 
Zeiger ptest zeigt.

Da der Zeiger auf die Variable test zeigt steht da jetzt 123 drin.

test    Variable vom Typ long
&test   Die Adresse der Variable test
ptest   Adresse die auf einen long Wert zeigt
*ptest  Der Wert auf den der Zeiger zeigt  (dereferenzieren)

von Ben j. (scarab)


Lesenswert?

Ich finde das
1
&netmask[0]
ist unnötig und dadurch ist der gesamte Ausdruck schlecht lesbar.
so gehts auch:
1
netmask
 da ein array ohne das [] ein Zeiger auf den ersten Wert des Arrays ist.
1
*((uint32*)au8_netmask) = *((uint32*)st_cache.au8_netmask);
2
//oder
3
*((uint32*)au8_netmask) = u32_irgendwas;
(möglicherweise kann man auch noch ein Paar Klammern weglassen, da bin 
ich mir im Moment aber nicht ganz sicher)

EDIT: vernünftige Compiler dürften mit solchen Ausdrücken keine Probleme 
haben. Ich habe sowas sowohl auf 8-Bit als auch auf 32-Bit Systemen 
verwendet. Immerhin gibts das casten von Zeigern schon seit über 20 
Jahren in C.

von Udo S. (urschmitt)


Lesenswert?

Benjamin F. schrieb:
> EDIT: vernünftige Compiler dürften mit solchen Ausdrücken keine Probleme
> haben. Ich habe sowas sowohl auf 8-Bit als auch auf 32-Bit Systemen
> verwendet. Immerhin gibts das casten von Zeigern schon seit über 20
> Jahren in C.
Nur das es etwas gibt heisst noch nicht daß es sinnvoll ist. Zumindest 
nicht hier.
Was machst du wenn auf IPv6 umgestellt wird?
Was machst du wenn das Byte Array nicht gepackt ist oder je nach 
Prozessor gar nicht gepackt werden kann?
...

Ich bleibe dabei das ist hier Schweinkramprogrammierung.

von Ben j. (scarab)


Lesenswert?

Udo Schmitt schrieb:
> Was machst du wenn auf IPv6 umgestellt wird?
IPv4 Server sind soweit ich weiß mit IPv6 nicht zu erreichen und 
umgekehrt, also muss man sowieso das Programm dementsprechend anpassen 
und man sollte dann auch gleich einen entsprechenden Datentyp 
definieren, z.B. ne union die sowohl v4 als auch v6 aufnehmen kann oder 
nen struct aus enum+union.

Mich würde eher interessieren was du machst wenn du z.B. so einen struct 
über UART verschickst und diesen auf der anderen Seite aus einem 
Byte-Array "wiederherstellen" musst.
1
typedef struct 
2
{
3
  EN_SOMEENUMERATION  en_irgendwas1;
4
  sint16              s16_irgendwas2;
5
  float               f32_irgendwas3;
6
  uint8               au8_irgendwas4[16];
7
  ST_SOMESTRUCT       st_irgendwas5;
8
}ST_MYSTRUCT;

Willst du sowas immer von Hand zusammen Bauen und wenn ja, wie willst du 
das enum und die Gleitkomma-Zahl aus dem Byte-Array bekommen?

von Mark B. (markbrandis)


Lesenswert?

Udo Schmitt schrieb:

> Schweinkramprogrammierung

Also das, was man in vielen Firmen jeden Tag auf der Arbeit sieht? ;-)

von Udo S. (urschmitt)


Lesenswert?

Benjamin F. schrieb:
> Willst du sowas immer von Hand zusammen Bauen und wenn ja, wie willst du
> das enum und die Gleitkomma-Zahl aus dem Byte-Array bekommen?
Was hat das damit zu tun, daß das casten eines byte arrays in einen Long 
nicht überall funktioniert und deshalb auf deutsch Kacke ist?

Zu deinem Beispiel:
Du willst ein enum von einem Rechner zu einem anderen schicken und 
erwartest daß der das noch richtig versteht?
Na viel Spass.
Hast du schon jemals komplexere Daten von einem Computer an einen 
anderen geschickt? Unterschiedlicher Bauart und unterschiedliche 
Betriebssysteme?
Dazu ist ein Protokoll da, daß eindeutig geklärt ist wie Daten zu 
interpretieren sind.
Su sollst es nicht von Hand machen aber du sollst eine Funktion 
schreiben die deine komplexe Daten in einer klar definierten Art und 
Weise in ein Byte Array schreibt und eine zweite die das auch wieder 
exakt so liest.
Dann kann man sogar von einem PC über eine Unix Kiste auf eine Vax mit 
MVS oder einen IBM Großrechner kommunizieren.
Wenn du es noch weiter treiben willst schau dir mal z.B. SOAP an. 
Stichwort "Webservice Kommunikationsprotokolle"

von Udo S. (urschmitt)


Lesenswert?

Mark Brandis schrieb:
> Also das, was man in vielen Firmen jeden Tag auf der Arbeit sieht? ;-)
Genau, täglich! Ich nehme mich auch nicht davon aus so ein Mist schon 
verbockt zu haben.
Aber man sollte versuchen lernfähig zu bleiben :-)

von Ben j. (scarab)


Lesenswert?

Udo Schmitt schrieb:
> Benjamin F. schrieb:
>> Willst du sowas immer von Hand zusammen Bauen und wenn ja, wie willst du
>> das enum und die Gleitkomma-Zahl aus dem Byte-Array bekommen?
> Was hat das damit zu tun, daß das casten eines byte arrays in einen Long
> nicht überall funktioniert und deshalb auf deutsch Kacke ist?

hast du dafür ein beispiel? wenn es beim casten von zeigern auf dem 
eigenen system zu fehlern kommt ist imo der compiler ganz ganz großer 
mist.

> Zu deinem Beispiel:
> Du willst ein enum von einem Rechner zu einem anderen schicken und
> erwartest daß der das noch richtig versteht?
> Na viel Spass.
> Hast du schon jemals komplexere Daten von einem Computer an einen
> anderen geschickt? Unterschiedlicher Bauart und unterschiedliche
> Betriebssysteme?
> Dazu ist ein Protokoll da, daß eindeutig geklärt ist wie Daten zu
> interpretieren sind.
> Su sollst es nicht von Hand machen aber du sollst eine Funktion
> schreiben die deine komplexe Daten in einer klar definierten Art und
> Weise in ein Byte Array schreibt und eine zweite die das auch wieder
> exakt so liest.
> Dann kann man sogar von einem PC über eine Unix Kiste auf eine Vax mit
> MVS oder einen IBM Großrechner kommunizieren.
> Wenn du es noch weiter treiben willst schau dir mal z.B. SOAP an.
> Stichwort "Webservice Kommunikationsprotokolle"

das man bei unterschiedlichen system und verschiedenen compilern noch 
mehr beachten muss ist klar aber was hat das damit zu tun das casten von 
zeigern generell zu verteufeln? mal davon abgesehen das es hier um uC 
geht und nicht um PCs...

von Udo S. (urschmitt)


Lesenswert?

Benjamin F. schrieb:
> hast du dafür ein beispiel? wenn es beim casten von zeigern auf dem
> eigenen system zu fehlern kommt ist imo der compiler ganz ganz großer
> mist.

Ich hatte es oben schon gesagt. Es gibt Systeme (auch zumindeste einige 
ältere 16 und 32 Bit Controller (ich glaube bestimmte DSPs) die 8 Bit 
Werte nicht wahlfrei hintereinander ablegen können/konnten. Dadurch sind 
Füllbytes/ungenutzte Bytes zwischen den einzelnen Bytes des Arrays.
Genau auf solchen Meschinen kracht sowas dann.
Also lässt man so einen Blödsinn eine for Schleife hat eine Zeile mehr 
und da ist es klar.

Andere Systeme brauchen deutlich mehr Zeit wenn sie byteweise auf 
ungerade Adressen zugreifen sollen, wenn du also den Compiler auf 
Geschwindigkeit optimieren lässt könnte es durchaus sein, daß er ein 
byte array nicht gepackt ablegt, sondern auch Füllbytes vergibt so daß 
der Zugriff schneller ist, dann krachts auch.

von Udo S. (urschmitt)


Lesenswert?

Benjamin F. schrieb:
> das casten von zeigern generell zu verteufeln?
Keiner verteufelt das casten als solches nur zeigt sich oft daß 90% der 
Casterei unnötig ist oder gar Fehler versteckt.

Hier ging es darum, daß man ein Char[4] Array einfach auf ein long 
castet was nicht immer und überall richtig ist.

von Ben j. (scarab)


Lesenswert?

nagut dann hab ich dich vielleicht falsch verstanden

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.