Cast short zu char!

Gast #4245542
Lesenswert?

Hallo,

ich habe eine kurze Anfängerfrage:

Ich muss ein unsigned short array mit bis zu maximal 100 Wörtern, an 
eine Funktion übergeben die anscheinend ein unsigned char-array als 
Eingangswert benötigt (laut Fehlermeldung des Compilers).
Konkret ist es eine Uart-Sende-Routine von meinem BlackFin. Nun meine 
Frage kann ich das irgendwie geschickt casten?
Mein alternativer Ansatz wäre : mit Bitoperatoren, Shiften und einer 
Schleife das short-array erst in ein char-array zu kopieren und dieses 
dann an die Uart-Routine zu übergeben.
Aber vllt kennt ja jemand von euch einen simpleren Ansatz.

Vielen Dank im Voraus!

Gruß
Gast #4245545
Lesenswert?

Welche Parameter braucht denn die Senderoutine genau?

Wenn sie keine Länge als Parameter hat, dann geht es nicht. Dann kann 
sie nur Strings senden und dann scheitert sie an der ersten \0 die 
vermutlich in deinen Shorts enthalten ist.
Gast #4245555
Lesenswert?

Sry hatte ich vergessen, ja das ist korrekt. Zusätzlich zu dem 
char-array bekommt die Routine die Anzahl der zu sendenden Bytes. Ich 
habe einfach die Anzahl der Wörter mit 2 multipliziert, das sollte ja 
die Anzahl an Bytes sein.

Hier mal der Rohbau der Senderoutine:
1
void RS232_OutData(unsigned char *String, unsigned int anzahl){
2
  int i;
3
  for (i = 0; i<anzahl;i++){
4
    RS232_OutChar(String[i]);
5
  }
6
}
Gast #4245581
Lesenswert?

Peter II schrieb:
> dann kannst du einfach casten.
> unsigned short Daten[100];
> RS232_OutData( (unsigned char *)Daten, sizeof( Daten ) );

Wäre es dann nicht so dass es einen Array-Überlauf gibt?
1
RS232_OutData( (unsigned char *)Daten, sizeof( Daten ) / 2 );
Wäre meiner Meinung nach richtiger oder?

Gruß Diek
Gast #4245584
Lesenswert?

Diek schrieb:
> Wäre es dann nicht so dass es einen Array-Überlauf gibt?RS232_OutData(
> (unsigned char *)Daten, sizeof( Daten ) / 2 );Wäre meiner Meinung nach
> richtiger oder?

Oder noch besser so:
1
RS232_OutData( 
2
> (unsigned char *)Daten, sizeof( Daten ) / sizeof(Daten[0]) );
#4245589
Lesenswert?

Diek schrieb:
> Peter II schrieb:
>> dann kannst du einfach casten.
>> unsigned short Daten[100];
>> RS232_OutData( (unsigned char *)Daten, sizeof( Daten ) );
>
> Wäre es dann nicht so dass es einen Array-Überlauf gibt?RS232_OutData(
> (unsigned char *)Daten, sizeof( Daten ) / 2 );Wäre meiner Meinung nach
> richtiger oder?
>
> Gruß Diek

Nein das ist falsch. Die Anzahl gibt ja an wie viele unsigned char 
gesendet werden sollen. Aus 100 shorts werden 200 chars.
#4245596
Lesenswert?

Ulrich F. schrieb:
>> RS232_OutData((unsigned char *)Daten, sizeof( Daten ) /
> sizeof(Daten[0]) );
> RS232_OutData((unsigned char *)Daten, sizeof( Daten ) * sizeof(Daten[0])
> );

Nein auch nicht. So wäre es am "richtigsten":
1
RS232_OutData( (unsigned char *)Daten, sizeof(Daten) / sizeof(unsigned char) );
Aber der C Standard garantiert sizeof(unsigned char) = 1, also kann man 
sich das sparen.
#4245606
Lesenswert?

Trundle Trollkönig schrieb:

> Ich
> habe einfach die Anzahl der Wörter mit 2 multipliziert

Nimm nicht 2, sondern sizeof(unsigned short) anstelle der 2. Oder noch 
besser:
1
    anzahlBytes = sizeof(*Daten) * anzahlElemente;

wenn der "Füllgrad" des Arrays variabel ist. Auf die Art hast du die 
Größe nur vom Array abhängig gemacht und musst nicht 2 'Informationen' 
im Einklang halten.
#4245625
Lesenswert?

Volker S. schrieb:
> Also ich würde bei dem ersten Vorschlag bleiben:
>
> Peter II schrieb:
>> dann kannst du einfach casten.
>> unsigned short Daten[100];
>> RS232_OutData( (unsigned char *)Daten, sizeof( Daten ) );
>
> Passt doch und gefällt mir besser als:
> RS232_OutData( (unsigned char *)Daten, 100*sizeof(unsigned short) );
>
> <edit> solange der "Füllgrad" nicht variabel ist...

Das ist noch schlimmer, als den Datentyp direkt im sizeof zu verwenden.
Jetzt hast du die Korrektheit des Aufrufs komplett von der Deklaration 
abhängig gemacht. Wann immer sich die Deklaration ändert, darfst du 
nicht vergessen, den Aufruf anzupassen.

Der springende Punkt ist:
schreibst du
1
  unsigned char Daten[100];
2

3
...
4

5
  RS232_OutData( (unsigned char *)Daten, sizeof(Daten) );

dann passt dir der Compiler die Byteangabe an. Und zwar macht der das 
immer korrekt (solange Daten in Arrayform sichtbar ist). Und genau das 
willst du haben: du willst, dass dir der Compiler die Dinge anpasst, die 
er anpassen kann und du willst dich als Programmierer davon entlasten. 
Die Praxis zeigt nämlich auch, warum man das will.
Gast #4245628
Lesenswert?

>void RS232_OutData(unsigned char *String, unsigned int anzahl){

Aus diesen Grund haben meine Senderoutinen gewöhnlich einen 
void-Pointer. Damit castest du einfach in der RS232_OutData-Routine auf 
das was Du intern brauchst. Und ausserhalb kann alles mitgegeben werden.
1
void RS232_OutData(void *data, unsigned int length )
2
{
3
  int            i = 0;
4
  unsigned char *String = data;
5
  while ( i < length  )
6
  {
7
    RS232_OutChar( String[i++] );
8
  }
9
}
#4245662
Lesenswert?

Karl H. schrieb:
> Das ist noch schlimmer, als den Datentyp direkt im sizeof zu verwenden.
> Jetzt hast du die Korrektheit des Aufrufs komplett von der Deklaration
> abhängig gemacht. Wann immer sich die Deklaration ändert, darfst du
> nicht vergessen, den Aufruf anzupassen.

Ähhhh, das war eigentlich so, dass ich deinen eigenen Vorschlag so 
gedeutet habe, als wolltest du es genau so "schlimm" anwenden, bevor du 
die Ergänzungen mit dem "Füllstand" gemacht hast...
#4245678
Lesenswert?

Volker S. schrieb:
> Karl H. schrieb:
>> Das ist noch schlimmer, als den Datentyp direkt im sizeof zu verwenden.
>> Jetzt hast du die Korrektheit des Aufrufs komplett von der Deklaration
>> abhängig gemacht. Wann immer sich die Deklaration ändert, darfst du
>> nicht vergessen, den Aufruf anzupassen.
>
> Ähhhh, das war eigentlich so, dass ich deinen eigenen Vorschlag so
> gedeutet habe, als wolltest du es genau so "schlimm" anwenden, bevor du
> die Ergänzungen mit dem "Füllstand" gemacht hast...

Ausgangspunkt war eigentlich, dass er die 2 direkt im Code hat.
Das ist die schlimmste aller Varianten.
Gast #4245681
Lesenswert?

Karl H. schrieb:
> Matthias L. schrieb:
>>>void RS232_OutData(unsigned char *String, unsigned int anzahl){
>>
>> Aus diesen Grund haben meine Senderoutinen gewöhnlich einen
>> void-Pointer.
>
> Yep.
> Und abgesehen davon, ist die Bezeichnung das Arguments mit 'String' grob
> irreführend. Das ist kein String, das sind einfach nur Bytes.

Seh ich nicht so.
void* ist ja im Grunde "Pointer auf weiß ich nicht". Aber der Typ ist ja 
bekannt, nämlich (mehrere) Bytes. Um das Problem mit dem String (wegen 
char) zu umgehen, fände ich das unten richtiger. Ist zwar intern das 
Gleiche, aber die Intention ist besser erkennbar.
1
#include <stdint.h>
2
void RS232_OutData(uint8_t *data, unsigned int anzahl);
Gast #4245687
Lesenswert?

test schrieb:
> Seh ich nicht so.
> void* ist ja im Grunde "Pointer auf weiß ich nicht". Aber der Typ ist ja
> bekannt, nämlich (mehrere) Bytes. Um das Problem mit dem String (wegen
> char) zu umgehen, fände ich das unten richtiger. Ist zwar intern das
> Gleiche, aber die Intention ist besser erkennbar.

Datei-Funktionen (read, write) verwenden auch void*. Daran würde ich mir 
auch orientieren. Dann kann der cast immer wegfallen.

Im Computer sind Daten immer ein Array von Byte.
#4245702
Lesenswert?

test schrieb:

> Seh ich nicht so.
> void* ist ja im Grunde "Pointer auf weiß ich nicht".

Eben.
'String' hat ja in C eine feststehende Bedeutung. Das ist eine Abfolge 
von Bytes, die mit einem 0 Byte endet.

> char) zu umgehen, fände ich das unten richtiger. Ist zwar intern das
> Gleiche, aber die Intention ist besser erkennbar.
>
>
1
#include <stdint.h>
2
> void RS232_OutData(uint8_t *data, unsigned int anzahl);

den void* finde ich schon ok. Aber so wie du würde ich das Argument 
'data' oder 'bytes' nennen und nicht 'String'. Denn das ist kein String 
im C-Sinne.
Und nein, das Argument, dass es dann ja wohl keine 'anzahl' geben würde, 
kann ich so auch nicht akzeptieren. Die strn* Funktionen nehmen auch 
eine Anzahl und behandeln einen String trotzdem als C-String.
Den void* würde ich trotzdem nehmen, weil er mir das ständige Casten 
beim Aufruf erspart. Davon hab ich nichts, wenn ich Argumente beim 
Aufruf dauern zurecht casten muss, es sein denn ich hab als Aufrufer 
zufällig uint8_t. Gerade bei derartigen Funktionen ist ein void* 
praktisch immer das Kennzeichen, dass man es mit rohen Bytes zu tun hat. 
Siehe zb den Unterschied zwischen den mem*() Funktionen und den str*() 
Funktionen. Die mem* Funktionen haben allesamt einen void*.
Gast #4245736
Lesenswert?

Eine Funktion, die auf Strings steht erwartet etwas wie:
'1', ' ', 'V', 'e', 'r', 's', 'u', 'c', 'h', '\0'.

Eine Funktion, die auf Arrays steht erwartet etwas wie:
'1', ' ', 'V', 'e', 'r', 's', 'u', 'c', 'h', '?', '?' mit Länge.
Hinter dem Array kann noch Rest vom letzten Mal stehen.

Ein short Array, gefüllt mit Zeichen sieht aber folgendermaßen aus:
'1', 0; ' ', 0; 'V', 0; 'e', 0; 'r', 0;
's', 0; 'u', 0; 'c', 0; 'h', 0; '?', 0; '?', 0 mit Länge.
Anstelle der Nullen kann auch irgendein Schmutz vorkommen.

Also geht nur Funktion umschreiben oder vor der Übergabe Array 
umkopieren.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren