Sooo grauslich finde ich es gar nicht: Das hier (klick) hatte ich schon die ganze Zeit im Hinterkopf
viele Grüße
Andreas
Ich hab das jetzt mit dem VC (microsoft visual studio 2005) durchprobiert. Das sollte eigentlich schon auf GCC übertragbar sein.
Vorweg:
Klammervarianten:Code:int* p = (char*)1000; // geht garnicht, verständlich, ist ja auch ein widerspruch
Code:int* p = (int*)1000;Code:(char*)p++; // kennen wir schon, liefert p+4 (int)p++; // ebenfalls p = (int*)(int)p++; // ebenfalls ((char*)p)++; // Mag er garnicht ==> error C2105: '++' needs l-value
Was geht ? (definitiv getestet)
Code:int tmp = (int)p; p = (int*)++temp;
Code:union { int* p; int iP; } un; un.p = (int*)1000; un.iP++ ; // (durch die union wird auch int*p mit-incrementiert
und die grausliche Variante
Code:p = (int*)((int)p + 1);
Wie gesagt: getestet
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Sooo grauslich finde ich es gar nicht: Das hier (klick) hatte ich schon die ganze Zeit im Hinterkopf
viele Grüße
Andreas
#define true ('/'/'/')
#define false ('-'-'-')
Was mir hier nicht klar ist:
wozu ist eine Funktion gut, die Daten vom Typ "weißnichtsogenau", und das ist void, in eine andere Funktion stopft, die nur mit chars umgehen kann. Sollte data mal auf ints oder floats zeigen, kommt etweder Müll raus, oder es crasht. Und die Verwendung von void-Pointern führt nur dazu, daß einem der Compiler nicht mehr helfen kann, Fehler zu vermeiden.
Es muß also heißen: uart_send(char* data, ... , und in Zukunft für jeden void* 5€ in die Kaffekasse (oder ersatzweise eine schriftliche Begründung von mindestens einer Seite, warum so etwas aus Gründen der Programmlogik wirklich nötig ist )!
MfG Klebwax
Strom fließt auch durch krumme Drähte !
zu PicNick
Sorry, ich muss mich korrigieren, deine Zeile
p = (int*) ((int)p + 1);
funktioniert wirklich. Erhöht den Zeiger um 1 und nicht um 4.
Hast Du völlig recht.
zu Klebwax:
wie soll man denn sonst eine universelle function schreiben ?
ich möchte verschiedene Datentypen, Strukturen und ähnliches
senden. Das Casten übernimmt bei mir die Funktion, ich brauche mich darum
nicht mehr zu kümmern. Ich übergebe nur noch die Adresse und die Anzahl Bytes.
int xx;
struct
char a,b,c,d;
int e,f,g;<
} st;
und zudem finde ich daß:
uart_send(&xx,sizeof(xx));
uart_send(&st,sizeof(st));
besser aussieht als:
uart_send((char*)&xx,sizeof(xx));
uart_send((char*)&st,sizeof(st));
aber das ist sicher Geschmackssache. Funktionieren tut natürlich beides. Was die Sicherheit angeht,
denke ich mal, nehmen sich beide Varianten nichts.
anbei meine 5,-- Euro...
Habt noch ein schönes Wochenende.
Siro
Ich frag jetzt mal garnicht, ob du das ernst meinst. Was du willst, geht garnicht. Man kann weder ein Int noch eine Struktur einach so über die serielle Schnittstelle versenden. Dein Compiler hat schon gewußt, warum er deinen Code nicht bearbeiten wollte, und du ihn erst mit void* und casts mundtot machen musstest.
Die 5€ kannst du behalten. Leg noch was drauf und kauf dir ein Buch über C und lerne. Und mach dir mal Gedanken über Strukturen, gepackt und ungepackt, auf verschiedenen CPUs mit 8 bis 64 Bit Wortbreite sowie Big und Little Endian und dann lerne was über robusten portablen Code und gewöhne dir einen solchen Stil an.
MfG Klebwax
Strom fließt auch durch krumme Drähte !
Ich muss hier sicher keine Rechenschaft ablegen, aber zu Klebwax:
ich möchte die Bytes so herausschicken, wie sie im Speicher stehen.
Ob sie gepackt sind oder im Intel oder Motorola Format vorliegen ist in MEINEM Falle völlig unwichtig,
Das ist lediglich ein Hexdump den ich zu Testzwecken herausschicke um SOFTWAREFEHLER AUFZUDECKEN.
Deshalb finde ich deine voreilige Beurteilung unberechtigt negativ, satt kreativ...
Dein Satz:
Was du willst, geht garnicht. Man kann weder ein Int noch eine Struktur einach so über die serielle Schnittstelle versenden.
ist in meinem Falle eine Falschaussage, denn es funktioniert ja einwandfrei.
Siro
Offenbar sind noch ein paar Leute ohne einen Schimmer, wie man wirklich professionelle Funktionen schreibt
z.B
void * memcpy ( void * destination, const void * source, size_t num );Das sind schon mal 15 €
http://www.cplusplus.com/reference/clibrary/cstring/memcpy
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Warum hast du dann nicht auch gleich das zweite Beispiel von Funktionen, für die soetwas wie ein void-Pointer überhaupt erfunden wurde, genannt: die Gruppe der Memory-Management-Funktionen. Die mehr als einseitige Begründung, wozu man so etwas braucht, findest du in der gängigen C-Literatur. Des gleichen findest du dort aber dort auch die Diskussionen, das eine richtige Programmiersprache Pointer, egal welcher Art, überhaupt nicht zulassen sollte. Offensichtlich haben Leute wie Wirth den Programmierern nicht zugetraut, vernüftig mit dem Instrument Pointer umzugehen.
Um aber bei "professionelle Funktionen" zu bleiben, glaubst du ernsthaft, so etwas wie das beschriebene uart_send() würde einem professionellen Code Review standhalten ? Wie verhält sich die Funktion, bei verschiedenen Compileroptimierungen oder auch verschieden Compilern, wie auf CPUs mit unterschiedlichen Wortbreiten, wie auf einer CPU mit anderen Alignment-Regeln, und wie bei Big oder Little Endian Rechnern?
MfG Klebwax
Strom fließt auch durch krumme Drähte !
Zum Thema void pointer hier ein Ausschnitt von learncpp.com: (hervorhebungen von mir)
Statt "Just make sure" hab ich gesagt, schreib eine ausführliche Begründung oder zahl in die Kaffekasse.In general, it is a good idea to avoid using void pointers unless absolutely necessary, as they effectively allow you to avoid type checking. This allows you to inadvertently do things that make no sense, and the compiler won’t complain about it.
.....
However, very occasionally, you may still find a reasonable use for the void pointer. Just make sure there isn’t a better (safer) way to do the same thing using other language mechanisms first!
MfG Klebwax
Strom fließt auch durch krumme Drähte !
Hmm, wie wärs mit folgendem Szenario:
Eine Funktion deren Rückgabewert ein Funktionspointer auf sich selbst ist (bzw. ganz allgemein ein Pointer auf eine Funktion des gleichen Typs).
Wenn du das ohne void* schaffst, gehört die Kaffeekasse dir
Zugegeben, sowas braucht man eher selten, aber ich habe auch noch ein praxisrelevantes Beispiel für dich:
Nehmen wir an du schreibst einen Low-Level Treiber für irgendeine Schnittstelle, sagen wir mal SPI. An dieser Schnittstelle können unterschiedlichste Geräte hängen, die wiederum eigene Treiber benötigen welche auf dem SPI Treiber aufsetzen. Bei solchen Treibern ist es üblich mit Callback-Funktionen zu arbeiten, damit das System nicht bei jeder Übertragung blockiert wird. Und aus eigener Erfahrung kann ich dir garantieren, daß du in einer Callback-Funktion mehr Informationen haben möchtest als nur ein Flag das dir sagt ob die Übertragung erfolgreich war oder nicht. Ein void-Pointer, der vom Low-Level Treiber einfach nur mitgeführt wird, erlaubt es dir beliebige Informationen an einen Job anzuhängen die dir dann in der Callback-Funktion wieder zur Verfügung stehen.
So viele Treppen und so wenig Zeit!
Lesezeichen