Hallo,
wie kann ich in C (nicht C++) die Länge eines Arrays/Strings ermitteln
wenn in den Nutzdaten alle Werte zw. 0-FF Verwendung finden?
Hintergund es geht um das versenden von Daten im TP2.0/KWP
CAN-Protokoll.
Die Länge der zu Übermittelnen Daten ist variabel.
Beispiel:
Länge 2.Bytes + Befehl/SID 1.Byte + variable Daten: 31(SID)+ 00 11 22 33
44 55 66 77 88 99 AA BB CC DD EE FF(Daten) sind insges. 17 Bytes
Übertagen wird dann:
Länge Befehl+Daten
00 11 31 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
Wie kann ich diese variable Länge am besten errechnen wenn es kein
"Ende" Zeichen gibt?
Gruß
Jackson
Michael S. schrieb:> Wie kann ich diese variable Länge am besten errechnen wenn es kein> "Ende" Zeichen gibt?
Gar nicht. Du musst die Länge explizit übergeben, ala:
Michael S. schrieb:> Länge Befehl+Daten> 00 11 31 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF>> Wie kann ich diese variable Länge am besten errechnen wenn es kein> "Ende" Zeichen gibt?
Die Länge steht in den ersten 2 Bytes (Big Endian): 0x0011, also 17
dezimal. Wobei die Länge selbst nicht in diese 17 Bytes eingerechnet
ist.
Danke erstmal für die Antworten!
Ich habe es noch anders gelöst indem ich die Hex-Werte in einem
ascii-String übergebe da gibt es ja \0 am Ende.
Sieht jetzt so aus:
SendObdCommand("31 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF");
Die Routine rechnet die ascii Hexzahlen in echte Hex-Werte/Bytes um und
zählt dann auch wieviele Bytes es waren. Danach verschickt sie dann die
Daten mit der errechneten Länge. Funzt wunderbar soweit.
Aber wie bekomme ich jetzt in das String noch variable Werte eingefügt?
Ich möchte Beispielsweise folgenden senden:
SendObdCommand("27 04" + zahl1 + zahl2 + "00");
Sollte dann folgendes übermitteln wenn zahl1=C3 und zahl2=02 ist:
SendObdCommand("27 04 C3 02 00");
Gruß
Jackson
Michael S. schrieb:> Ich habe es noch anders gelöst indem ich die Hex-Werte in einem> ascii-String übergebe da gibt es ja \0 am Ende.
Das ist nicht dein Ernst?! Du willst die Binärdaten erst in einen
Hexa-ASCII-String konvertieren, an eine Funktion übergeben, und in der
wieder dekodieren, nur weil du es nicht schaffst die Länge zu
übergeben?!
Michael S. schrieb:> SendObdCommand("27 04" + zahl1 + zahl2 + "00");
^-- in diesem Fall weißt du ja scheinbar schon dass deine Binärdaten 4
Bytes lang sind. Was spricht dagegen, diese "4" explizit mit zu
übergeben?!
1
chardata[]={0x24,0x04,zahl1,zahl2};
2
SendObdCommand(data,4);
3
...
4
voidSendObdCommand(char*data,size_tlength){
5
// Schleife über alle Bytes
6
for(inti=0;i<length;i++){
7
sendByte(data[i]);// Ein Byte senden...
8
}
9
}
So sparst du dir die rechen&speicher aufwändige En&De-Kodierung und es
funktioniert auch!
Das Problem ist nicht die Länge zu übergeben sondern jedesmal mühselig
die Länge von Hand zu zählen... Teilweise längen von über 80 Bytes und
viele Befehle hintereinander! Wenn man sich da mal verzählt kommt das
ganze Protokoll durcheinander und man sucht sich dussselig nach dem
Fehler...
Der MC ist schnell genug und soll das für mich erledigen.
Wie kann ich den in C zwei Zeichenkette zusammenfügen?
SendObdCommand("27 04" + "00");
oder wenn c="11 22"
SendObdCommand("27 04" + c);
Michael S. schrieb:> Das Problem ist nicht die Länge zu übergeben sondern jedesmal mühselig> die Länge von Hand zu zählen...
Auch keine Problem, das kann der Compiler.
1
charmyData[]={1,2,3,4,zahl1,zahl2,5,6,7,42};
2
SendObdCommand(data,sizeof(myData));
Michael S. schrieb:> Wie kann ich den in C zwei Zeichenkette zusammenfügen?
Indem du die Längen der Zeichenketten zählst (ha!) und eine Zeichenkette
der Länge dieser Summe anlegst, und die einzelnen hineinkopierst:
Das ist, besonders auf Plattformen wie AVR, extrem ineffizient. Und
sag mir nicht man könne sich nicht leicht vertun bei der
Offset-Rechnerei mit den richtigen -1 an den richtigen Stellen.
Zusammenfassend kann man sagen dass du es unfassbar umständlich und
ineffizient machst, es geht viel einfacher und viel effizienter.
Eingentlich wollte ich jetzt schreiben: kauf und lese ein C-Buch.
Aber das erspar ich mir.
Jemand möchte Can programmieren, und hat schon beim einfachsten C
Probleme?
Dr. Sommer schrieb:> Michael S. schrieb:>> Das Problem ist nicht die Länge zu übergeben sondern jedesmal mühselig>> die Länge von Hand zu zählen...> Auch keine Problem, das kann der Compiler.>
1
charmyData[]={1,2,3,4,zahl1,zahl2,5,6,7,42};
2
>SendObdCommand(mydata,sizeof(myData));
>
OK, und wie mache ich das wenn myData immer wieder andere Daten/Längen
hat
Michael S. schrieb:> Dr. Sommer schrieb:>> Michael S. schrieb:>>> Das Problem ist nicht die Länge zu übergeben sondern jedesmal mühselig>>> die Länge von Hand zu zählen...>> Auch keine Problem, das kann der Compiler.>>char myData [] = { 1, 2, 3, 4, zahl1, zahl2, 5, 6, 7, 42 };>> SendObdCommand (mydata, sizeof(myData));>> OK, und wie mache ich das wenn myData immer wieder andere Daten/Längen> hat> char myData [] = { 1, 2, 3, 4, zahl1, zahl2, 5, 6, 7, 42 };> SendObdCommand (mydata, sizeof(myData));> neue Daten mit verschiedenen längen in myData
Wie kommen die neuen Daten denn nach myData? Hol die Länge dieser Daten
von deren Quelle. Die muß sie ja wissen.
Wenn du partout die Länge nicht übergeben möchtest, könntest du auch so
was ähnliches wie SLIP encoding machen. Führe ein Escape-Byte ein (zB
0xFF), dann kannst du zB End-Of-Data als (0xFF 0x00) kodieren, und ein
eigentliches 0xFF in den Datenbytes als (0xFF 0xFF). Es würden dann
sogar noch 254 andere Kontroll-Bytes übrig bleiben...
Aber das ist trotzdem nur eine pfuschige Behelfslösung an der Stelle,
übergib die Länge separat (wie von allen empfohlen)
Wir reden aneinander vorbei, bislang sah meine main() so aus (Zufall das
hier grade die Länge immer 2 ist, kann wie gesagt auch anders sein):
1
//Init Obd Session
2
SendObdCommand("10 89");
3
ReceiveObdCommand();
4
SendObdCommand("1A 9B");
5
ReceiveObdCommand();
6
SendObdCommand("27 03");
7
ReceiveObdCommand();
Die Komandos müssen alle einzelnt gesendet werden und es wird vom
Emfänger auf jedes einzelne Komando eine Antwort zurück geschickt die
mit ReceiveObdCommand gelesen wird und ggf. danach auch ausgewertet
werden muss.
Und richtig, CAN kann pro Message max. 8 Byte übertragen.
Dafür ist ja SendObdCommand gedacht, die zerhackt und verschickt die
Daten dann im TP2.0 Protokoll als Single oder Multimessages je nach
Datenlänge.
Die Lösung ist Top danke!
Perfekt wäre jetzt nur noch wenn die Länge immer als short (2Byte Wert)
vor die eigendlichen Daten gestellt würde, dann bräuchte ich die Länge
nicht noch einzel an die Send...Routine übergeben. Ist das auch so
"einfach" möglich? Beispiel:
1
{chardata[]={0x10,0x89};// + irgendwie sizeof Länge davor?
Michael S. schrieb:> Perfekt wäre jetzt nur noch wenn die Länge immer als short (2Byte Wert)> vor die eigendlichen Daten gestellt würde, dann bräuchte ich die Länge> nicht noch einzel an die Send...Routine übergeben.
Vielleicht geht das irgendwie lustig mit variadischen Makros, aber sonst
wüsste ich jetzt spontan keine Möglichkeit in C. In C++ ists einfach:
Möglichkeit #1: Komplettes Array übergeben und decayen lassen:
1
#include<iostream>
2
3
// Eigentliche Sendefunktion
4
voidSendObdCommandInt(constchar*data,size_tsize){
5
for(inti=0;i<size;i++){
6
std::cout<<(int)data[i];
7
}
8
}
9
10
// Proxy-Funktion um automatisch die Größe zu bestimmen
11
template<typenameT>
12
inlinevoidSendObdCommand(constT&data){
13
SendObdCommandInt(data,sizeof(data));
14
}
15
16
intmain(){
17
SendObdCommand((char[]){1,2,3,4,5});
18
SendObdCommand((char[]){3,42});
19
}
Möglichkeit #2: Array-Initializer als Argumente übergeben und Array
zusammenbauen:
1
#include<iostream>
2
3
// Eigentliche Sendefunktion
4
voidSendObdCommandInt(constchar*data,size_tsize){
5
for(inti=0;i<size;i++){
6
std::cout<<(int)data[i];
7
}
8
}
9
10
// Proxy-Funktion um automatisch Array zu erstellen und mit Größe zu übergeben
@xfr: Wäre jedesmal weniger zu tippen und sähe natürlich sauberer aus,
aber leider schmeisst er nen Syntaxfehler:
*** ..\src\main.c(397) E4062C: syntax error near `;'
*** ..\src\main.c(397) E4062C: syntax error near `)'
*** ..\src\main.c(397) E4189C: automatic symbol has zero or negative
size
bezogen auf Zeile:
SEND_OBD_COMMAND({0x10, 0x89});
Michael S. schrieb:> @xfr: Wäre jedesmal weniger zu tippen und sähe natürlich sauberer aus,> aber leider schmeisst er nen Syntaxfehler:
Hm, habs mir schon fast gedacht. Hatte den Code nicht getestet ...
Na gut, dann eben doch per variadischem Makro, der Compiler muss dann
aber C99 unterstützen:
Zu Deinem zweiten Problem:
Wenn der Wert der Variable z erst zur Laufzeit bekannt ist, wirst Du
nicht drumrum kommen, die Daten von Hand zusammenzubauen bzw. als
eigenen Parameter an die Funktion zu übergeben. Ein Array kann in C nur
mit Daten initialisiert werden, die schon zur Compilezeit bekannt sind.
Michael S. schrieb:> @xfr: geht leider auch nicht, er mag _VA_ARGS_ nicht...> Wie geschrieben leider nur c und kein c++ compiler...
C kann das. Definiert ist das bei mir (Watcom C) in stdarg.h.
Also ich würde hier zwei Möglichkeiten vorschlagen:
a) Definiere dir eine Struktur, welche das Kommando + läge enthält.
Dann kannst du dir für jedes Kommando eine benannte Konstante anlegen,
mußt maximal einmal zählen (falls man das nicht irgendwie trickreich im
Init erledigen lassen kann). und kannst in der Folge dan sehr bequem
damit arbeiten. Auch Erweiterungen sind so sehr einfach möglich.
Außerdem wäre es der Architekturtechnisch sauberste Weg.
c) VARG Funktion, welche aber alle Daten mit dem nächstgrößerem Datentyp
(z.B. int) entgegennimmt und einen Wert > 0xFF als "Ende-Zeichen"
definiert.
Nachteil: Doppelter Stackverbrauch, gechaste, magic numbers...
Aus Interesse, was fuer eine Plattform ist das denn, dass es keinen C++
Compiler gibt und selbst C derart eingeschraenkt ist? Da muesste man
dann ja einen Bogen drum machen...
Der Compiler heisst fcc907s und ist für die Fujistu FX16 Serie
http://www.fujitsu.com/downloads/MICRO/fma/pdfmcu/CM42-00328-3E.pdf
Wenn ich die stdarg.h mit einbinde nimmt er die VA_ARGS aber bei
SEND_OBD_COMMAND(0x10, 0x89);
SEND_OBD_COMMAND(0x1A, 0x9A);
SEND_OBD_COMMAND(0x27, 0x03);
hat er dann immer noch Syntaxfehler und ich weis nicht wieso...
Michael S. schrieb:> hat er dann immer noch Syntaxfehler und ich weis nicht wieso...
Lass dir doch mal das Ergebnis des C Preprocessings ausgeben (beim GCC
ginge das mit der Compileroption -E, bei deinem keine Ahnung) dann sieht
man leichter was falsch sein könnte...