Forum: PC-Programmierung C++ .. ne Zahl an was dranhängen


von Nils (Gast)


Lesenswert?

Hallo zusammen,

ich habe folgende Funktion:

void usbInterface_LPC2148::methodSwitchLEDOn ( int LEDNr )
{
  BYTE datagram[16];
  memcpy( datagram, ("\0sMI \3 \5"), 16 );
  usbInterface::write( datagram );
}

jetzt würde ich gerne da wo die \5 steht, den inhalt der LEDNr variable 
haben. wie bau ich das da noch dran

memcpy( datagram, ("\0sMI \3 "+LEDNr), 16 );

geht leider nicht, ich denke da werden dann wohl die zahlen 
zusammenaddiert oder sowas.

von SiO2 (Gast)


Lesenswert?

strcp() oder so aehnlich sollte gehen.

von Thomas B. (yahp) Benutzerseite


Lesenswert?

datagram[x] = LEDNr;

x ist durch Auszählen zu bestimmen. Das ganze muss natürlich nach dem 
memcpy geschehen und geht nur, wenn die Position fest ist, also der 
String davor unveränderlich.

von Björn (Gast)


Lesenswert?

@Thomas B.
Bitte?????


Ich gehe mal davon aus, dass der int-Wert LEDNr in einen String 
gewandelt werden soll. Dazu gibt es in C++ Stringstreams. Nach alter 
C-Sitte könntest du es auch mit sprintf machen:

sprintf(datagramm, "\0sMI \3 %u", LEDNr);

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hat sich eigentlich schon mal jemand diese merkwürdige Stringkonstante 
näher angesehen, die da per memcpy kopiert werden soll? Die ist, wenn 
ich mich nicht völlig verzähle, gerade mal 8 Bytes lang; memcpy wird 
aber angewiesen, 16 Bytes zu kopieren.

Als Argument für sprintf eignet sich dieser String gar nicht, da die \0 
als erstes Zeichen den String bereits terminiert, sprintf also die 
Formatanweisung nicht versteht.

Aber selbst wenn es das täte, wäre die Formatanweisung fehlerhaft, 
anstelle %u müsste schon %c verwendet werden.

von Thomas B. (yahp) Benutzerseite


Lesenswert?

Danke!

Datagramm ist kein String, sondern ein Array von chars. Da macht sprintf 
wenig Sinn. Die LED Nummer ist im obigen Beispiel mit einem Backslash 
geschrieben, d. h. es ist offenbar gerade keine literale Interpretation 
der LED Nummer gewünscht, sondern der Wert selbst (obwohl \ mit 
dezimaler Notation eigentlich nicht auftreten dürfte).

Wenn er ein Backslash übertragen will, müsste er es im String doppelt 
schreiben.

Davon abgesehen kann man natürlich erstmal einen String bauen, in dem 
alles sauber drinn steht - dort kann man dann auch mit sprintf operieren 
- und danach alles nach Datagramm kopieren. Ist die sauberste, 
wartbarste, zur Laufzeit vermutlich uneffizientest und 
"hochsprachlichste" Lösung.

Punkt 1 ist aber die Klärung, wie die Zahl dort gewünscht wird, in ASCII 
Repräsentation oder nicht.

von Björn (Gast)


Lesenswert?

Richtig! Ich habe die \\ beim kopieren vergessen. Warum aber der Integer 
LEDNr durch sprintf als char interpretiert werden soll ist mir ein 
Rätsel??? !

Kann natürlich so sein, ist aber genau so unwahrscheinlich (oder 
wahrscheinlich) wie %u oder %d

In C gibt es keinen String-Datentyp sondern Strings werden als Arrays 
von chars dargestellt... (aber das wisst ihr ja eh beide) deshalb noch 
mehr???? von mir....

Und ob man in einem C++ Programm ohne Not mit memcpy rumeiern sollte 
darf zumindest in Frage gestellt werden. Wenn ich schon C++ verwende, 
dann kann ich ja deren Mechanismen verwenden, oder (stringstreams 
eben)?!

  string strData(dataStream.str());
  stringstream dataStream;

  dataStream << "\\0sMI \\3 \\5" << LEDNr;

  strData = dataStream.str();

Wobei write ja nun auch noch irgend wo her wissen muss, wie groß das 
datagramm ist oder?

von Björn (Gast)


Lesenswert?

Mist schon wieder falsch kopiert!!! Soll heißen:

  string strData;
  stringstream dataStream;

  dataStream << "\\0sMI \\3 \\5" << LEDNr;

  strData = dataStream.str();

von Karl H. (kbuchegg)


Lesenswert?

> Warum aber der Integer LEDNr durch sprintf als char interpretiert
> werden soll ist mir ein Rätsel??? !

Oh. Das muss es nicht. Auch ein char ist letztendlich ein
skalarer Typ, der eine ganze Zahl repräsentiert. Der wichtiste
Unterschied (neben seiner Größe) besteht darin, dass char und
int während Ausgaben / Eingaben (und natürlich bei der damit
zusammenhängenden Formatierung) anders behandelt werden.
Während bei einem int durch Verwendung von %d oder %u oder ...
eine Konvertierung der Zahl in eine ASCII Repräsentierung erzwungen
wird, wird bei der Ausgabe als char, erzwungen durch %c, der int
direkt, quasi binär, in den Ausgabestream eingefügt.

> Kann natürlich so sein, ist aber genau so unwahrscheinlich (oder
> wahrscheinlich) wie %u oder %d

Nö. Das ist tatsächlich so.

Zum Rest kann ich nichts sagen, da mir immer noch unklar ist,
wie denn das Ergebnis auf Byteebene aussehen soll. Der springende
Punkt ist immer noch der: Soll die LedNr als ASCII-Repräsentierung
der Zahl eingebaut sein oder soll im Datagramm der binäre Wert
der LedNr auftauchen.

von Nils (Gast)


Lesenswert?

Hallo zusammen,

danke, dass ihr euch so viele Gedanken zu meiner Frage gemacht habt. Das 
was übertragen werden soll ich tatsächlich 5 und nicht der ASCII Code 
von 5.

Im Moment mache ich das zwar noch in einem C++ Programm, aber irgendwann 
soll ein LPC2148 das ganze auch sprechen. Diese komische Zeichenfolge 
gehört zu einem Protokoll, dass ich implementieren will.

Es geht immer mit 0 los (für USB), dann kommt ein s und dann (M)ethod 
(i)nitialisierung, dann die nummer der funktion  die aufgerufen werden 
soll und dann die Parameter. Im Moment hat das Board, was ich verwende 8 
LEDs also die Frage ob dezimal oder hexadezimal war noch gar nicht 
relevant.

Ich werde jetzt mal versuchen, mir nen schönen String vorher zu bauen 
und den dann mit memcpy reinzuschreiben.

grüße Nils

von Karl heinz B. (kbucheg)


Lesenswert?

Wenn ich was vorschlagen darf:
Denk dir für die binäre \0 was anderes aus.
Irgendwann benutzt du string Funktionen dafür,
warum auch nicht, und dann ist dir diese \0 ewig im Weg.

Du könntest zb folgendes machen:

#define SET_LED_FUNCTION 3

void usbInterface_LPC2148::methodSwitchLEDOn ( int LEDNr )
{
  BYTE datagram[16];
  sprintf( datagram, "%csMI%c%c", '\0', SET_LED_FUNCTION, LedNr );
  usbInterface::write( datagram );
}

Das zusätzliche Argument '\0' zu sprintf ist zb. nur deswegen
notwendig, weil du '\0' so nicht in den Format-String einbauen
kannst.

Wenn du auf die str... Familie verzichten willst, dann musst du
selbst auf die Längen acht geben. So was wie:

  memcpy( datagram, ("\0sMI \3 \5"), 16 );

ist kein Kavaliersdelikt! Der String "\0sMI \3 \5" ist nun mal
keine 16 Zeichen lang. Genau genommen, hat er als String eine
Länge von 0 Bytes (wieder: wegen dem \0 da ganz am Anfang).
Man könnte auch argumentieren, dass er ein deklarierte Länge
von 9 Bytes besitzt. Wie auch immer: Er ist auf jeden Fall
keine 16 Bytes lang.

von Nils (Gast)


Lesenswert?

Ne das mit der 0 weglassen geht nicht, da das fest im USB Protokoll drin 
ist. Ich könnte Sie natürlich erst in der write Funktion, die ich 
geschrieben habe einbauen.

von Björn (Gast)


Lesenswert?

@ Karl heinz Buchegger
"
> Kann natürlich so sein, ist aber genau so unwahrscheinlich (oder
> wahrscheinlich) wie %u oder %d

Nö. Das ist tatsächlich so.

Zum Rest kann ich nichts sagen, da mir immer noch unklar ist,
wie denn das Ergebnis auf Byteebene aussehen soll. Der springende
Punkt ist immer noch der: Soll die LedNr als ASCII-Repräsentierung
der Zahl eingebaut sein oder soll im Datagramm der binäre Wert
der LedNr auftauchen.
"

Ich glaube, da haben wir an einander vorbei geredet. Weil mit meiner 
Aussage nichts anderes ausdrücken wollte, als das was dein springender 
Punkt ist.

Deinem zweiten Posting stimme ich im Übrigen uneingeschränkt zu.

von Nils (Gast)


Lesenswert?

@Karl Heinz:

Danke schonmal, aber leider bekomme ich folgende Fehlermeldung:

error C2664: 'sprintf' : cannot convert parameter 1 from 'BYTE *' to 
'char *'

und das bei diesem code:

void usbInterface_LPC2148::methodSwitchLEDOn ( int LEDNr )
{
  BYTE* datagram = new BYTE[Capabilities.OutputReportByteLength];
  sprintf( datagram, "%csMI%c%c", '\0', METHOD_SET_LED, LEDNr );
  usbInterface::write( datagram );
}

woran liegt das denn ?

#define METHOD_SET_LED 3

hab ich auch drüber stehen.

von Εrnst B. (ernst)


Lesenswert?

sprintf will als ersten parameter einen char *, du gibst ihm einen BYTE 
*.

BYTE ist bei dir warscheinlich ein typedef auf unsigned char...

Wobei ich immer noch nicht verstehe, warum sich JEDER eigene Typedefs 
für solche int-Datentypen baut, wo's doch mit #include <stdint.h> 
schöne, standartisierte gibt, z.B. uint8_t, int8_t, int32_t usw...

/Ernst

von Nils (Gast)


Lesenswert?

@ernst

danke, aber leider weiss ich jetzt nicht was ich machen soll, wie kann 
ich sprintf trotzdem verwenden?

grüße Nils

von Εrnst B. (ernst)


Lesenswert?

sprintf( static_cast<char *>(datagram), "%csMI%c%c", '\0', 
METHOD_SET_LED, LEDNr ); // C++ style cast

oder

sprintf( (char *)datagram, "%csMI%c%c", '\0', METHOD_SET_LED, LEDNr ); 
/* C style cast */

von Thomas B. (yahp) Benutzerseite


Lesenswert?

Na, du könntest direkt in dem sprintf-Aufruf datagramm auf char* casten. 
Allerdings nur, wenn du dir sicher bist, da die Datentypen soweit 
kompatibel sind, dass nix passiert.

Ansonsten wäre zu empfehlen, diese PASCAL-Style Typedefs nicht zu 
verwenden ;-)

von Nils (Gast)


Lesenswert?

@ernst:

also version 1:

error C2440: 'static_cast' : cannot convert from 'BYTE *' to 'char *'

und bei version2 klappts, danke

von Εrnst B. (ernst)


Lesenswert?

Nils wrote:

> error C2440: 'static_cast' : cannot convert from 'BYTE *' to 'char *'

Das darf eigentlich nicht sein, wie ist den dein "BYTE" deklariert?

von Nils (Gast)


Lesenswert?

@ernst: Oje, da  fragst du mich was, ich bin leider (halb) blutiger 
Anfänger, wenn du mir sagt wie ich das rausfinde, dann schau ich nach.

von Nils (Gast)


Lesenswert?

ok habs:

//windef.h
typedef unsigned char       BYTE;

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.