Moin Forum,
ich stehe gerade aufm Schlauch und brauch mal Hilfe.
Ich möchte ein Array aufbauen, in dem n structs enthalten sind.
1
typedefstructtstConfigParam{
2
uint8_tRegister;
3
uint8_tLength;
4
constchar*Content;
5
}tstConfigParam;
6
7
tstConfigParamMyParamList[]={
8
/*0*/{0x23,4,"abcd"},
9
/*1*/{0x45,6,"efghij"},
10
/*2*/{0x67,2,{0x55,0x66}}/* <<<--- Fehler */
11
};
Bei der Initialisierung der Werte würde ich aber gerne den String aus
Konstanten aufbauen lassen. Also der Compiler soll die 0x55 und 0x66 in
den Flash legen und den Zeiger darauf hier in die Liste eintragen, so
wie es mit den Zeichenfolgen "abcd" auch funktioniert.
Ja, ich könnte auch
1
"\x55\x66"
schreiben, aber das geht leider nicht wenn ich die 0x55 aus einem
1
2
#define Value1 0x55
3
#define Value2 0x66
entnehmen will.
Ich würde aber auch gerne vermeiden noch extra Variablen auzulegen.
Gibts da eine Möglichkeit?
Rangi J. schrieb:> /*2*/ { 0x67, 2, {0x55, 0x66}} /* <<<--- Fehler */
Weil ein const char* erwartet wird, du aber gar kein Array hast, von dem
du einen Zeiger bilden kannst. Das müsstest du schon erst noch bauen:
Ja, das geht natürlich, aber ich wollte ja gerade vermeiden, noch extra
Variablen anzulegen. Ziel ist, das in diesem Array in einigermaßen
übersichtlicher Art eine Liste von Konfigurationsparametern als Tabelle
zusammengestellt werden. Für eine Handvoll Parameter mag das gehen, aber
dann wirds schnell unübersichtlich.
Und bei den Strings "abcd" gehts ja auch. Die müssen auch nicht extra
irgendwo angelegt werden.
Rangi J. schrieb:> /*2*/ { 0x67, 2, {0x55, 0x66}} /* <<<--- Fehler */Jörg W. schrieb:> /*2*/ { 0x67, 2, "\x55" "\x66" },
Früher oder später wird das Programm abstürzen, weil der Content Pointer
an eine Funktion übergeben wird, die auf einen String-Terminator
angewiesen ist. Das sind die typischen Fehler die erst in einem halben
Jahr auftreten.
Also wenn schon denn schon, das eine Byte für den Terminator investieren
:
Oliver S. schrieb:> 0x55 0x66 soll wohl den String "Uf" ergeben, nicht "0x550x66".
sorry, ja. Mit 0x geht es nicht so einfach. Und wenn es formatspezifisch
ist, kann man es eh vergessen.
Johann L. schrieb:> Funktioniert leider nicht in allen Situationen:
Das Compound Literal befindet sich dort im Scope der Funktion. Das ist
ein bisschen wie eine anonyme lokale Variable.
Ab C23 kann man auch im Compound Literal einen Storage Class Specifier
angeben, dann geht das:
Oliver S. schrieb:> Nicht wirklich...>> 0x55 0x66 soll wohl den String "Uf" ergeben, nicht "0x550x66".
Darauf bin ich vorhin auch reingefallen ... aber ich hab's dann noch
gemerkt ("stringify" ...)
Rangi J. schrieb:> Ich würde aber auch gerne vermeiden noch extra Variablen auzulegen.> Gibts da eine Möglichkeit?
Was generell schon mal ungünstig ist.
Zeiger bringen eine gewisse Flexibilität, aber man sollte sich damit
auskennen.
Für die Stack-Navigation z.B. braucht man immer auch eine Schrittbreite.
Ohne geht einfach nicht.
(Verschachtelte Schleifen können auch hilfreich sein.)
Bruno V. schrieb:> Oliver S. schrieb:>> 0x55 0x66 soll wohl den String "Uf" ergeben, nicht "0x550x66".>> sorry, ja. Mit 0x geht es nicht so einfach. Und wenn es formatspezifisch> ist, kann man es eh vergessen.
Wobei sich da schon die nach dem Warum für diese Forderung stellt.
Oliver
Oliver S. schrieb:> Wobei sich da schon die nach dem Warum für diese Forderung stellt.
Was ich meine: Für Dezimal oder Octal geht das define ja mit "\" am
Anfang. Aber wenn jemand 0x55 schreiben will und dafür ein anderes
#define braucht, dann ist meine Lösung immer murx.
Oliver S. schrieb:> Was ich meine: wenn er „Uf“ haben will, das schon zur Compilezeit weiß,> warum definiert er dann nicht „U“ und „f“.
Vielleicht ist die Anwendung die Ausgabe von Sonderzeichen, die nicht im
Quelltextzeichenvorrat enthalten sind oder in diesem eine andere
Codierung haben, als für die Anwendung gebraucht wird.
Ein Beispiel wären Sonderzeichen auf den üblichen HD44780-Displays.
Da kann man im Quelltext nicht "Ä" schreiben, wenn "Ä" auf dem Display
erscheinen soll.
Harald K. schrieb:> Ein Beispiel wären Sonderzeichen auf den üblichen HD44780-Displays.
Da kann man sich aber auch anders helfen, ich habe hier beispielsweise
sowas:
Jörg W. schrieb:> Da kann man sich aber auch anders helfen
Im Prinzip ja, wenn man aber den numerischen Wert auch noch braucht ...
obwohl, den hat man ja:
1
#define BATLEFT_EMPTY "\x01"
2
3
#define BATLEFT_EMPTY_VALUE BATLEFT_EMPTY[0]
Und auf die Weise lässt sich des Threadstarters Problem dann doch lösen:
Bruno V. schrieb:> Wenn es wichtig ist, dass es wirklich ein String ist (also mit> \0-Endung),
Nein, im Gegenteil, in diesem Fall sind in dem "String"
Gerätekonfigurationsdaten enthalten. Da kommen sehr häufig 0x0 vor, ein
Null-terminierter String ist hier nicht sinnvoll.
Oliver S. schrieb:> 0x55 0x66 soll wohl den String "Uf" ergeben
Ja, korrekt, aber es ist halt nur ein Platzhalter für irgendwelche
Daten. "Uf" hat keinen Textbezug.
Daniel A. schrieb:> Ab C23 kann man auch im Compound Literal einen Storage Class Specifier> angeben
Ich verwende die Cube-IDE. Und das nimmt der Compiler so ohne zu
meckern:
Rbx schrieb:>> Ich würde aber auch gerne vermeiden noch extra Variablen auzulegen.>> Gibts da eine Möglichkeit?>> Was generell schon mal ungünstig ist.
Warum? Macht in meinem Fall gar keinen Sinn, aber "generell" ...
Oliver S. schrieb:> Was ich meine: wenn er „Uf“ haben will, das schon zur Compilezeit weiß,> warum definiert er dann nicht „U“ und „f“.
Ja, exakt, da steht z.B. für einen ADXL355-Sensor folgendes:
1
/*! register values */
2
#define ADXL355_DEVID_AD_VALUE (0xAD) //Analog Devices ID
3
#define ADXL355_DEVID_MST_VALUE (0x1D) //Analog Devices MEMS ID
4
#define ADXL355_PARTID_VALUE (0xED) //Device ID 0xED (355 octal)
Für andere Geräte steht da natürlich ganz was anderes. Und in dem
Beispiel muss im Flash zum Schluss eine Zeichenkette "AD 1D ED" stehen.
In der Liste ein Zeiger auf diese 3 Bytes.
Harald K. schrieb:> Und auf die Weise lässt sich des Threadstarters Problem dann doch lösen:
Ja und nein, genau sowas wollte ich ja gerade vermeiden. Damit habe ich
viele Zeilen Code mit Inhalt verteilt über unterschiedliche Sektionen.
Dadurch schleichen sich ganz schnell Copy n Paste Fehler ein. Ja bei
kleinen Listen mag das schleichen, aber wenn da über 50 Zeilen stehen,
blickt da keiner mehr durch. In dem Beispiel von oben mit dem ADXL355
ist das ein Einzeiler:
TLDR:
Mit dem Cast "const uint8_t[]" funktioniert es genau wie gewünscht. Auf
dem Bild sieht man, das die Liste im Flash steht, der Zeiger demzufolge
auch. Und auch die Daten stehen im Flash. Wahlweise kann der Zeiger auch
auf den Ram zeigen, und auch das geht.
Gelöst
Rangi J. schrieb:> a gerade vermeiden. Damit habe ich> viele Zeilen Code mit Inhalt verteilt über unterschiedliche Sektionen.
Nö, Du hättest nur exakt zwei #defines statt einem, und der numerische
Wert stünde auch nur in einem davon.
Das ist der einzige Unterschied.
1
#define ADXL355_DEVID_AD_STR "\xAD" //Analog Devices ID
Das funktioniert dann auch mit älteren C-Dialekten (es gibt immer noch
freilaufende Systeme, die kein C99 verstehen).
Aber gut, der andere Ansatz ist natürlich auch einer, wenn man sich
seines Compilers sicher ist.
Jörg W. schrieb:> Harald K. schrieb:>> Ein Beispiel wären Sonderzeichen auf den üblichen HD44780-Displays.>> Da kann man sich aber auch anders helfen, ich habe hier beispielsweise
[... Zeichen im CG-RAM ...]
Jörg W. schrieb:> oder> #define MY "\xe4"> const char units_lcd[] = " m" MY "npf";> const char units_iso[] = " mµnpf";
Für die Batterie-Icons ist das ja ok. Aber für Text? Muss das sein?
Macht man das so? Wenn man das "ganz unten" im Treiber macht (ja, zur
Laufzeit), bleibt der Quelltext doch ein wenig lesbarer. Soviel Zeit und
Flash muss sein ;)
Rangi J. schrieb:> Für andere Geräte steht da natürlich ganz was anderes. Und in dem> Beispiel muss im Flash zum Schluss eine Zeichenkette "AD 1D ED" stehen.> In der Liste ein Zeiger auf diese 3 Bytes.
Ganz generell: Wenn es immer 3 Byte sind, kann sich das ruhig im
Datentyp widerspiegeln. Also z.B. ein 3-Byte-Array.
Wenn Du 50 verschiedene dieser Structs hast, ggf. auf mehrere Files
verteilt, dann macht es durchaus Sinn, diese Structs in den Files
zusammenzufassen und nur den ptr zu veröffentlichen. Es ist sogar
möglich, diese Liste vom Linker erstellen zu lassen. Das erfordert aber
einige Erfahrung mit Linker-Sections.
Kurz gesagt: Es gibt 2 Möglichkeiten.
A) Du brauchst diese #defines (z.B. ADXL355_DEVID_AD_STR) im ganzen
Code, dann stehen die in einer Header und Du packst sie irgendwo
zusammen. Aber nicht zentral, sondern im jeweiligen Modul.
B) Du greifst auf diese Werte eher über Strukturen zu, dann brauchst Du
die #defines gar nicht bzw. wenn, nur lokal.