Ich habe ein uint8_t array mit einer Grösse von 16 Byte. Ich möchte nun
ein zweites Array initialisieren, welches auf die letzen 8 Byte zeigt,
ohne die Information der Grösse zu verlieren. Also anstatt
uint8_t grosses_array[16];
uint8_t* kleines_array = grosses_array+8;
will ich etwas in der Art:
uint8_t grosses_array[16];
uint8_t kleines_array[8] = grosses_array+8;
so dass sizeof(kleines_array) == 8 ist. Ist das in C möglich, oder
bleibt mir nichts anders übrig als das ganze Array entweder zu kopieren,
oder die Grösse in einer separaten Variable zu speichern?
Johnny B. schrieb:> hambi schrieb:>> oder die Grösse in einer separaten Variable zu speichern>> Entweder so oder mittels #define (Konstante).
Besten Dank für deine Antwort, werde ich wohl so machen.
Arduino Fanboy D. schrieb:> memcpy() ?
Täusche ich mich oder kopiert das die Daten? Ich will nicht für die
gleiche Information zweifachen Speicher belegen, deshalb möchte ich es
als Referenz haben.
Oliver S. schrieb:> Da Arrays in C ja sowieso keine Größeninfo besitzen,
Zur Compilezeit ist die noch da, deshalb liefert da sizeof() auch noch
was anderes als bei einem als normalen Pointer deklarierten Pointer.
Apollo M. schrieb:> ... noch eine variante!>> union {> uint8_t g[16];> uint8_t kl[8];> uint8_t kh[8];> } array;>> mt
Die letzten beiden sind identisch. Alle union-member fangen immer bei
offset 0 an.
Bernd K. schrieb:> Die letzten beiden sind identisch. Alle union-member fangen immer bei> offset 0 an.
ok, stimmt - guter hinweis. doch wieder nicht richtig nachgedacht.
mt
hambi schrieb:> so dass sizeof(kleines_array) == 8 ist.
Ist die Größe zur Compile-Time bekannt? Oder kann der Offset zum großen
Array erst at Runtime bestimmt werden?
Wenn bekannt, dann kannst Du das über die obige Struct in der Union
lösen.
Wenn nicht, musst Du die Größeninformation in einer separaten Variablen
mitführen.
Apollo M. schrieb:> DPA schrieb:>> uint8_t (*const kleines_array)[8] =>> (uint8_t(*const)[8])&grosses_array[8];>> ... kannst du hierzu mal etwas erklärendes schreiben?
uint8_t (*const kleines_array)[8] definiert einen konstanten Pointer auf
ein uint8_t Array mit 8 elementen. Ein Array hat eine Adresse, wo die
Daten stehen, aber diese muss nicht zwangsläufig irgendwo gespeichert
sein, und kann nicht geändert werden. Compiler vermeiden eigentlich
immer eine unnötige dereferenzierung, wenn man einen Pointer auf ein
Array nutzt, um auf das Array zuzugreifen, indem sie im Pointer die
Adresse des Arrays speichern, statt irgendwo die Adresse
zwischenzuspeichern, und dann darauf zu zeigen. Mit anderen Worten, der
Compiler behandelt einen Pointer auf ein Array vergleichbar zu einem
Pointer auf dessen Daten. Desshalb ist bei einem Array wie grosses_array
in der regel (void*)grosses_array==(void*)&grosses_array; Deshalb kann
ich ein uint8_t[] oder uint8_t* nach uint8_t(*)[] Casten. Ist aber
vermutlich hochgradig UB. Ich hol mir also einen Pointer auf das Array
startend bei Element 8, und kaste es in ein Pointer auf ein Array mit 8
Elementen, was implementationsbedingt eigentlich überall zufällig geht,
weil es in beiden fällen pracktischerweise gleich dereferenziert wird.
In meinem Beispiel sind eigentlich alle Zeilen mit Casts UB, glaub ich.
Der Rest ist aber 100% OK.
tut irgendwie das selbe, ohne so bedrohlich zu wirken. :)
Nachdem kleines_array so oder so ein Pointer ist, liefert der Ausdruck
sizeof(kleines_array) immer nur den Wert 4, in der Fassung von DPA
genauso wie in meiner.
Gruß
Herby
DPA schrieb:> uint8_t (*const kleines_array)[8] definiert einen konstanten Pointer auf> ein uint8_t Array mit 8 elementen.
Das definiert ein Array von Pointern auf const int, und ist damit
vermutlich nicht das, was gewünscht war.
Aber da der TO sich nicht dazu auslässt, was er überhaupt vorhat, weiß
sowieso niemand, was gewünscht ist.
Oliver
DPA schrieb:> In meinem Beispiel sind eigentlich alle Zeilen mit Casts UB, glaub ich.> Der Rest ist aber 100% OK.
Wenn ich die ISO-Norm nicht missverstehe, ist dein Code völlig korrekt
und legal, denn:
Das Hin- und Her-Casten zwischen verschiedenen Pointer-Typen wird
nirgends verboten, Einschränkungen gibt es lediglich bei direkter
Zuweisung ohne Cast-Operator.
Der Ausdruck
1
(*kleines_array)[i]
mit dem um die Ecke herum auf ein Element von grosses_array zugriffen
wird, ist ebenfalls in Ordnung, weil dieser Ausdruck und das Element,
auf das er zugreift, denselben Typ haben (nämlich uint8_t), womit die
"strict aliasing rule" (ISO-Norm Abschnitt 6.5, Absatz 7) befolgt wird.
Herbert P. schrieb:> Jaaa, aber...> ...> uint8_t *kleines_array = &grosses_array[8];> ...> printf("(*kleines_array)[%d] = %d\n", i, kleines_array[i]);> ...>> tut irgendwie das selbe, ohne so bedrohlich zu wirken. :)
Nicht ganz: Du kannst sizeof nicht verwenden, um die Größe des kleinen
Arrays zu ermitteln.
Der TE möchte aber,
hambi schrieb:> dass sizeof(kleines_array) == 8 ist.
Das ist zwar bei bei DPAs Vorschlag auch nicht der Fall, aber zumindest
gilt dort
1
sizeof*kleines_array==8
Man könnte diesen (und andere) Schönheitsfehler noch mit
1
#define kleines_array (*kleines_array)
beheben, muss dabei aber beachten, dass Makros einen größeren Scope als
Variablennamen haben.
DPA schrieb:> void example(uint8_t e[8]){> // AHTUNG: kein sizeof auf e anwenden!> for(int i=0; i<8; i++)> printf("e[%d] = %d\n",i,(int)e[i]);> }
... ich denke, das ist "böse"!
weil unnötigerweise hier ein array im daten stack angelegt wird und
nicht wie gewünscht als referenz.
mt
Herbert P. schrieb:> sizeof(kleines_array) immer nur den Wert 4, in der Fassung von DPA> genauso wie in meiner.
... das wäre ja auch logisch, weil das die grösse des pointer's ist -
und auch noch abhängig von der zielplattform.
mt
Apollo M. schrieb:> DPA schrieb:>> void example(uint8_t e[8]){>> // AHTUNG: kein sizeof auf e anwenden!>> for(int i=0; i<8; i++)>> printf("e[%d] = %d\n",i,(int)e[i]);>> }>> ... ich denke, das ist "böse"!>> weil unnötigerweise hier ein array im daten stack angelegt wird und> nicht wie gewünscht als referenz.
Legt er hier überhaupt eins an oder ist das nur ne verschrobene Art nen
Pointer hinzuschreiben?
DPA schrieb:> und kaste es in ein Pointer auf ein Array mit 8> Elementen,
... das ist für mich nur zum schein und auch kein voodo.
ob da 8, 128 oder 0 steht ist dem compiler egal, nur der daten typ des
array's ist interessant.
daher ist die ganze anweisung für mich murks, weil sie nichts bewirkt,
was ich nicht auch viel einfacher realisieren kann.
auch diese idee macht für mich nicht richtig sinn
void example2d(int n, int m, uint8_t e[n][m]){...
und auch das gleiche wie
void example2d(int n, int m) {
uint8_t e[n][m]);
...
}
mt
Bernd K. schrieb:> Legt er hier überhaupt eins an oder ist das nur ne verschrobene Art nen> Pointer hinzuschreiben?
nix pointer voodo!
... diese anweisung erzeugt ein speicher objekt und wird komplett
initialisert mit einer kopie des array's.
mt
Apollo M. schrieb:> ... diese anweisung erzeugt ein speicher objekt und wird komplett> initialisert mit einer kopie des array's.
Welcher C-Standard soll das sein?
Apollo M. schrieb:> Bernd K. schrieb:>> Legt er hier überhaupt eins an oder ist das nur ne verschrobene Art nen>> Pointer hinzuschreiben?>> nix pointer voodo!>> ... diese anweisung erzeugt ein speicher objekt und wird komplett> initialisert mit einer kopie des array's.
Blödsinn. Wäre dass tatsächlich der Fall, würde das hier nicht gehen:
1
#include<stdio.h>
2
3
voidtest(intn,intm,intx[n][m]){
4
intk=1;
5
for(inti=0;i<n;i++)
6
for(intj=0;j<m;j++)
7
x[i][j]=k++;
8
}
9
10
intmain(){
11
intx[3][4]={0};
12
test(3,4,x);
13
for(inti=0;i<3;i++)
14
for(intj=0;j<4;j++)
15
printf("x[%d][%d] = %d\n",i,j,x[i][j]);
16
}
Apollo M. schrieb:> auch diese idee macht für mich nicht richtig sinn>> void example2d(int n, int m, uint8_t e[n][m]){...
Ist doch einfacher uint8_t e[n][m] zu verwenden und e[i][j] anzugeben,
als uint8_t* e; und dann jedesmal mit e[i+j*n] das Feld manuell
berechnen zu müssen.
Oliver S. schrieb:> DPA schrieb:>> uint8_t (*const kleines_array)[8] definiert einen konstanten Pointer auf>> ein uint8_t Array mit 8 elementen.>> Das definiert ein Array von Pointern auf const int, und ist damit> vermutlich nicht das, was gewünscht war.
Nö, ein Array von Pointern auf const int wäre "const int*
kleines_array[8]".
Dieser Thread schreit mikrocontroller.net von oben bis unten.
Der Threadersteller, der mit großer Wahrscheinlichkeit den Unterschied
zwischen Stack und globalen Variablen nicht kennt, macht sich Sorgen um
8 Byte "Speicherverbrauch".
Dann berät man in zwei dutzend Antworten darüber wie man das Array
umcasten kann ohne ein einziges Mal zu erwähnen wie sinnlos das Ganze
ist, wenn der entstehende Pointer auf jeder halbwegs modernen Platform
bereits die Hälfte der neuen Array-Größe in Anspruch nehmen würde.
Und damit der Threadersteller auch ja nichts lernt voted man sinnvolle
Antworten wie "memcpy" oder "C Arrays besitzen keine Längeninfo" noch
schön runter...
Grandios :)
Daniel A. schrieb:> Oliver S. schrieb:>> DPA schrieb:>>> uint8_t (*const kleines_array)[8] definiert einen konstanten Pointer auf>>> ein uint8_t Array mit 8 elementen.>>>> Das definiert ein Array von Pointern auf const int, und ist damit>> vermutlich nicht das, was gewünscht war.>> Nö, ein Array von Pointern auf const int wäre "const int*> kleines_array[8]".
Ja, war mein Fehler.
Oliver
Daniel A. schrieb:> Ist doch einfacher uint8_t e[n][m] zu verwenden und e[i][j] anzugeben,> als uint8_t* e; und dann jedesmal mit e[i+j*n] das Feld manuell> berechnen zu müssen.
ja sieht besser aus, ich muss wohl nochmals in meine denkstube gehen -
bin ganz wirr :/)
mt
Oliver S. schrieb:> Daniel A. schrieb:>> Oliver S. schrieb:>>> DPA schrieb:>>>> uint8_t (*const kleines_array)[8] definiert einen konstanten Pointer auf>>>> ein uint8_t Array mit 8 elementen.>>>>>> Das definiert ein Array von Pointern auf const int, und ist damit>>> vermutlich nicht das, was gewünscht war.>>>> Nö, ein Array von Pointern auf const int wäre "const int*>> kleines_array[8]".
BTW weil solche Deklarationen oft falsch sind, cdecl hilft:
Vincent H. schrieb:> Dann berät man in zwei dutzend Antworten darüber wie man das Array> umcasten kann ohne ein einziges Mal zu erwähnen wie sinnlos das Ganze> ist, wenn der entstehende Pointer auf jeder halbwegs modernen Platform> bereits die Hälfte der neuen Array-Größe in Anspruch nehmen würde.
Wenn du dieser Zeile
DPA schrieb:> uint8_t (*const kleines_array)[8] = (uint8_t(*const)[8])&grosses_array[8];
ein static voranstellst, belegt die Pointer-Variable kleines_array
exakt 0 Bytes an Speicher, weil sie vom Compiler gar nicht erst angelegt
wird.
Ich hatte zwar selber noch nie den Fall, wo ich ein solches Konstrukt
wirklich sinnvoll einsetzen konnte, kann mir aber solche Fälle durchaus
vorstellen. Man kann nun entweder über Sinn und Unsinn der Fragestellung
philosophieren oder versuchen, die Frage – einfach so wie sie gestellt
ist – bestmöglich zu beantworten. Bernd und DPA haben sich für letzteres
entschieden. Ist das wirklich so schlimm?
Bernds Vorschlag mit der Union ist gut und richtig, DPAs Weg über den
Array-Pointer gefällt mir noch etwas besser, weil dort das Original-
Array grosses_array in genau der gleichen Weise verwendet werden kann
als gäbe es den Subarray-Alias kleines_array gar nicht.
Noch besser wäre es wenn auch kleines_array ohne den Umweg über die
Union (bei Bernd) oder die Pointer-Dereferenzierung (bei DPA) wie ein
ganz normales Array verwendet werden könnte, das ist aber in C IMHO gar
nicht möglich.
Vincent H. schrieb:> Und damit der Threadersteller auch ja nichts lernt voted man sinnvolle> Antworten wie "memcpy" oder "C Arrays besitzen keine Längeninfo" noch> schön runter...
Man kommt aber an die Längeninfo von Arrays mit sizeof ran.
Und da fing das Probblem beim TO ja auch an.
Er wollte das sizeof ja weiterjhin nehmen.
Hätte er von Anfang an eine Variable/#define/enum dafür genommen, wäre
das Problem nicht vorhanden.
Dirk B. schrieb:> Vincent H. schrieb:>> Und damit der Threadersteller auch ja nichts lernt voted man sinnvolle>> Antworten wie "memcpy" oder "C Arrays besitzen keine Längeninfo" noch>> schön runter...>> Man kommt aber an die Längeninfo von Arrays mit sizeof ran.
Nur wenn der Arraybezeichner noch nicht zur einem Zeigertyp zerfallen
ist.
Niklas G. schrieb:> In C++ könnte man eine Referenz umcasten. Ist aber ziemlich hässlich.
Ich würde in C++ std::span<> dafür einsetzen, und natürlich std::array
von Anfang an ...
Wilhelm M. schrieb:> Ich würde in C++ std::span<> dafür einsetzen, und natürlich std::array> von Anfang an ...Vincent H. schrieb:> Und damit der Threadersteller auch ja nichts lernt voted man sinnvolle> Antworten wie "memcpy" oder "C Arrays besitzen keine Längeninfo" noch> schön runter...
Er wollte es aber genau so haben! Und da es in diesem Forum ja verpönt
ist den Sinn der Frage anzuzweifeln und alternative Lösungswege
aufzuzeigen...
Niklas G. schrieb:> Wilhelm M. schrieb:>> Ich würde in C++ std::span<> dafür einsetzen, und natürlich std::array>> von Anfang an ...>> Vincent H. schrieb:>> Und damit der Threadersteller auch ja nichts lernt voted man sinnvolle>> Antworten wie "memcpy" oder "C Arrays besitzen keine Längeninfo" noch>> schön runter...>> Er wollte es aber genau so haben! Und da es in diesem Forum ja verpönt> ist den Sinn der Frage anzuzweifeln und alternative Lösungswege> aufzuzeigen...
Na, den Sinn einer Frage würde ich nicht anzweifeln, aber alternative
Lösungswege sollte man immer aufzeigen ... jedenfalls werde ich daran
festhalten ;-)
Wilhelm M. schrieb:> Nur wenn der Arraybezeichner noch nicht zur einem Zeigertyp zerfallen> ist.
Dann ist es auch kein Array mehr.
auch wenn es wie eines aussehen mag.
Dirk B. schrieb:> Wilhelm M. schrieb:>> Nur wenn der Arraybezeichner noch nicht zur einem Zeigertyp zerfallen>> ist.>> Dann ist es auch kein Array mehr.
Doch, das Objekt ändert sich nicht.
Wilhelm M. schrieb:> Dirk B. schrieb:>> Wilhelm M. schrieb:>>> Nur wenn der Arraybezeichner noch nicht zur einem Zeigertyp zerfallen>>> ist.>>>> Dann ist es auch kein Array mehr.>> Doch, das Objekt ändert sich nicht.
Es ist ja auch nicht das Objekt, das zerfällt, sondern der Ausdruck, der
das Objekt referenziert. Dieser ist nach dem Zerfall im Beispiel von
grosses_array nicht mehr vom Typ uint8_t[16] (Array), sondern vom Typ
uint8_t* (Pointer).
Vincent H. schrieb:> macht sich Sorgen um> 8 Byte "Speicherverbrauch".
Das hat er nicht geschrieben. Es gibt noch mehr Gründe warum man
irgendwo mal lieber eine Referenz als eine Kopie haben will.
Besten Dank für eure vielen und sachlichen Antworten. Ich werde mal die
Lösungen von Bernd und DPA ausprobieren.
Es geht darum, dass ich über BLE von verschiedenen Perpherals
verschiedenen Daten empfange. Diese sind dann in einem uint8_t Array
gespeichert, wessen Grösse bei Compilezeit bekannt ist. Zur Verarbeitung
dieser Daten muss ich sie in kleinere Array's füllen, was ich nur
ungerne mit Copy machen würde. Da jedes Peripheral andere Daten sendet,
wird jedes "Teilarray" nur einmal verwendet, d.h. deren Grösse variiert
mit dem Peripheral. Wenn ich sizeof verwenden kann, dann brauche ich nur
einmal anzugeben wie gross das Array ist, und kann danach auf sizeof
zurückgreifen. Es wäre natürlich möglich diese Information in
verschiedenen Define's zu speichern, was aber den Code aufbläst für eine
Information, welche (wenn sizeof das korrekte gibt) nur zum deklarieren
verwendet wird.
Besten Dank an euch alle, Hambi
hambi schrieb:> Zur Verarbeitung dieser Daten muss ich sie in kleinere Array's füllen
Warum?
hambi schrieb:> Es wäre natürlich möglich diese Information in verschiedenen Define's zu> speichern, was aber den Code aufbläst für eine Information, welche (wenn> sizeof das korrekte gibt) nur zum deklarieren verwendet wird
Ok du jetzt eine Zeile mit define oder eine Zeile mit hässlichem Cast
hast...
Vielleicht hilft dir in dem Zusammenhang auch Serialisierung.
hambi schrieb:> was aber den Code aufbläst für eine> Information,
Nein.
Magic Numbers sind doof.
hambi schrieb:> uint8_t grosses_array[16];> uint8_t kleines_array[8] = grosses_array+8;
Die 16 ist schon doof, gehört in ein #define. Schon kann man auf das
sizeof verzichten.
Bei der 8 genauso.
hambi schrieb:> Es geht darum, dass ich über BLE von verschiedenen Perpherals> verschiedenen Daten empfange. Diese sind dann in einem uint8_t Array> gespeichert, wessen Grösse bei Compilezeit bekannt ist. Zur Verarbeitung> dieser Daten muss ich sie in kleinere Array's füllen, was ich nur> ungerne mit Copy machen würde.
Ich würde ja einfach ein Struct mit Pointer + Grössenangabe nehmen:
1
typedefstructble_data{
2
uint8_t*data;
3
size_tlength;
4
}ble_data_t;
Oder bei verschiedenen BLE structs den typ mitspeichern, und dann ne
lookup tabelle:
1
// .h
2
enumble_dev_type{
3
BLE_DEV_T_BLA,
4
BLE_DEV_T_BLUB
5
};
6
7
struct_ble_type_info{
8
size_tdata_size;
9
};
10
11
structble_dev{
12
enumble_dev_typetype;
13
};
14
15
structble_dev_bla{
16
structble_devble;
17
intwhatever;
18
...
19
};
20
21
structble_dev_blub{
22
structble_devble;
23
intblablub;
24
...
25
};
26
27
28
// .c
29
conststruct_ble_type_infoble_type_info={
30
[BLE_DEV_T_BLA]={
31
.data_size=16;
32
},
33
[BLE_DEV_T_BLUB]={
34
.data_size=24;
35
},
36
}
Und dann ble_dev_bla.ble.type immer mit BLE_DEV_T_BLA initialisieren,
damit man die grösse bei jedem ble_dev mit
ble_type_info[ble_dev.ble.type].data_size abfragen kann. Mit dem Typ
kann man dann auch mit nem switch wieder von nem generischen "struct
ble_dev" zu einem ble_dev_bla oder ble_dev_blub kommen.
Falls man keine runtime typ infos will, aber ein struct pro datensatz,
und keine upcasts braucht, gibt es seit c11 auch _Generic:
1
structble_bla{...};
2
structble_blub{...};
3
4
#define BLE_DATA_SIZE(X) _Generic((X), \
5
ble_bla: 12ul, \
6
ble_blub: 23ul \
7
)
Dann kann man später so zeug machen: "struct ble_bla bla;
printf("%lu\n",BLE_DATA_SIZE(bla));" Ausgabe 12.
Jenachdem, was genau gebraucht wird.
Niklas G. schrieb:> In C++ (...) Ist aber ziemlich hässlich.
Redundant. Letzteres folgt aus Ersterem. Schönheit und Eleganz des
Quelltextes gehören nicht zu den Stärken von C++.
hambi schrieb:> Da jedes Peripheral andere Daten sendet,> wird jedes "Teilarray" nur einmal verwendet, d.h. deren Grösse variiert> mit dem Peripheral. Wenn ich sizeof verwenden kann, dann brauche ich nur> einmal anzugeben wie gross das Array ist
Irgendwo musst Du die Grössen so oder so angeben, daher bleibe ich bei
meiner ursprünglichen Meinung, dies mit einem sprechend benannten
#define an einer Stelle im Code zu tun.
Guter Code ist auch solcher, welchen auch Leute verstehen, die keinen
Doktor in C Programmierung gemacht haben.
Nachdenklicher schrieb:> Redundant. Letzteres folgt aus Ersterem. Schönheit und Eleganz des> Quelltextes gehören nicht zu den Stärken von C++.
Genau wie bei C. Man darf darauf hoffen dass Rust hier aufräumen wird...
Niklas Gürtler schrieb:> Nachdenklicher schrieb:>> Redundant. Letzteres folgt aus Ersterem. Schönheit und Eleganz des>> Quelltextes gehören nicht zu den Stärken von C++.>> Genau wie bei C. Man darf darauf hoffen dass Rust hier aufräumen wird...
Ich finde, bei C ist das viel einfacher als bei C++. Wenn man es richtig
beherrscht ist es fast so versatil wie C++, aber es gibt nur wenige,
klar festgelegte Konstrukte, statt viele verschiedene, um dinge damit
umzusetzen. Damit ist es schwieriger, durch Verwendung aller möglicher
Features Verwirrung zu stiften. Es ist immer eine Kunst, schönen und
Lesbaren Code zu schreiben, ohne Spagetticode, Romanfunktionen &
Dateien, oder Feature-Überkomplexifizierung zu betreiben. Wenn man C
Code schön strukturiert, geht das meiner Meinung nach meistens aber sehr
gut. Ich hatte auch schon läute, die überacht waren, als sie einen
einfach verständlichen JavaScript Code gesehen haben. Das wichtigste
ist, dass alles an einem Ort ist, wo es sinn macht. Dass man die
Struktur ansieht, und denkt, "das müsste dort sein", und es dann
tatsächlich dort ist, und es im Idealfall dann nur ein paar simple
Funktionen und Datenstrukturen sind, dessen Zweck man sofort versteht.
Oft macht es auch sinn, die Kontrolle über Listeneinträge usw.
umzukehren, also z.B. die Implementationen von dingen sich selbst
registrieren lassen, statt eine Liste zu nehmen wo alle Implementationen
drin sind. (siehe z.B. linker listen in uboot, oder meinen linker hacks
artikel im wiki). Aber aufpassen, wenn man das übertreibt und mit event
Systemen koppelt, kann man den überblick verlieren wie etwas von x nach
y kommt. Und bei total anderen Funktionen am besten ein anderes Projekt
nehmen, ne library generieren, und ein möglichst schlankes und stabiles
Interface im voraus definieren. Man kann übrigens in git auch submodule
auf andere branches im selben repo machen. Man braucht aber immer viel
Übung, und es ist sinvoll ein Refactoring immer sofort zu machen, statt
zu warten. Zusammengefasst: Der Code ist gut, wenn man das gesuchte ohne
grosses Vorwissen sofort dort findet, wo man es erwartet, und man immer
sehr schnell sieht, woher etwas aufgerufen werden kann, welche Abläufe
es gibt, und was die machen, bzw. wo die Informationen überall
durchgeschoben werden. Oh, und nein, Rust kann auch nicht verhindern,
dass jemand schlechten Code schreibt, keine Sprache kann das. Ausser
Brainfuck, dort gibt es keinen besseren oder schlechteren code.
DPA schrieb:> void example(uint8_t e[8]){> // AHTUNG: kein sizeof auf e anwenden!> }
Das ist richtig, aber da es dem TO ja um kleines_array und dessen Größe
ging, kann man deinen array-pointer tatscählich auch dort mit sizeof()
verwenden: