Hallo, bei folgendem Code-Fragment #if sizeof(char)>1 #warning "Size zu gross!" #endif bringt der GCC 3.4.6 die Fehlermeldung ../main.c:240:11: missing binary operator before token "(" (Zeile 240 ist die "#if sizeof(char)>1") Der Code ist in Realität größer, aber ich habe den Fehler mal auf diesen Miminal-Code reduziert. Kann mir jemand einen Hinweis geben, warum dem Compiler das nicht gefällt? Ansonsten funktioniert sizeof in den Funktionen einwandfrei. Danke schon mal. Günter
Frage 6.5: Funktioniert der sizeof-Operator in Präprozessor-Direktiven? Antwort: Nein. Präprozessing findet in einer Phase der Übersetzung statt, zu der noch keine Typinformation verfügbar ist. Statt 'sizeof' können die in <limits.h> vordefinierten Konstanten verwendet werden. Noch besser ist es natürlich, das Programm so zu schreiben, dass es unabhängig von der Grösse bestimmter Typen ist. References: ANSI Sec. 2.1.1.2, Sec. 3.8.1 footnote 83; ISO Sec. 5.1.1.2, Sec. 6.8.1; H&S Sec. 7.11.1 p. 225.
Hallo, Minetti, danke für diesen Hinweis. Damit ist die Sache klar. Das Programm ist durchaus unabhängig von der Größe bestimmter Typen, mit dem sizeof-Konstrukt prüfe ich eine komplexere Sache ab, wollte hier aber den kleinstmöglichen Nenner bringen, um nicht zu viel erklären zu müssen. Aber wenn sizeof zum Präprocessing seine Antwort noch nicht bringt - was mir jetzt nach besserem nachdenken klar ist - dann muß ich die Sache anders lösen, was leicht möglich ist. Jedenfalls hast Du mir weitergeholfen. Danke. Günter
Wenn du C++ verwendest, kannst du aus der BOOST-Library das static_assert verwenden - damit kann man solche Dinge so ähnlich abprüfen, wie du das mit dem Preprozessor versucht hast. static_assert benutzt nicht den Prepozessor, sondern Templates.
Uhu Uhuhu wrote:
> Wenn du C++ verwendest, kannst du aus der BOOST-Library das
Danke, Uhu, aber ich benutze "nur" C, nicht C++, somit muß ich wohl
darauf verzichten.
Das o.g. Konstrukt dient ja nur zum Abfangen von eventuellen
Programmierfehlern, ich habe es jetzt als C-Code eingebaut, so braucht
es zwar etwas ROM-Bereich, funktioniert aber einwandfrei.
Bei besseren Compilern darfst du davon ausgehen, dass "if"-Anweisungen mit dem Compiler bereits bekanntem Ausgang entsprechend optimiert werden.
Was schon immer im C-Standard verfügbar ist: assert. man assert liefert:
1 | NAME |
2 | assert - abort the program if assertion is false |
3 | |
4 | SYNOPSIS |
5 | #include <assert.h> |
6 | |
7 | void assert(scalar expression); |
8 | ... |
Darin kannst Du problemlos sizeof verwenden. Aufruf: assert (sizeof(char)==1); ==1 deshalb, weil assert bei false abbricht.
Andreas Kaiser wrote: > Bei besseren Compilern darfst du davon ausgehen, dass "if"-Anweisungen > mit dem Compiler bereits bekanntem Ausgang entsprechend optimiert > werden. [ ] Du hast die Frage des OP verstanden. [ ] Du hast die Antwort aus der C-Bibel gelesen.
> [ ] Du hast die Frage des OP verstanden. Gebe ich dir recht. > [ ] Du hast die Antwort aus der C-Bibel gelesen. Bin ich aber seltsamerweise nicht der einzige. Nachgeholt: sizeof(char) ist per Definition 1.
Hallo, was mich mal interessieren würde ist wenn ich z.B. char b definiere und das auf einen ARM (32Bit) braucht dann b 4 Byte oder nur 1 Byte? Gruß Florian
> was mich mal interessieren würde ist wenn ich z.B. char b definiere und > das auf einen ARM (32Bit) braucht dann b 4 Byte oder nur 1 Byte? Kommt darauf an, was du mit "Byte" meinst. In C braucht char per Definition immer genau ein Byte, denn so ist das Byte dort definiert. Wenn du eigentlich ein Oktett meinst, dann kommt es in der Theorie auf den Compiler an. Er hat da freie Hand, da C nur definiert, daß ein Byte mindestens 8 Bit breit sein muß. Es darf aber auch 32 Bit breit sein. In der Praxis ist ein Byte aber fast immer 8 Bit groß. Auf einem ARM kannst du davon ausgehen.
Welche Länge ein char nun tatsächlich hat müsste aus der erwähnten limits.h des Compilers hervorgehen. Gruss Oops
@all danke für die superschnelle antwort also ich war eigentlich auch der Meinung das ein Byte immer 8 Bit sind und ein char eigentlich auch... es geht nur darum kann ich den Speicher (3 Byte) die noch als overhead da sind benutzen oder kann man die nicht mehr allozieren? Geht nicht um ein spezielles Problem.. aber kann interessant werden bei größeren Byte Arrays in einem 32Bit system... man kann den compiler ja auch zwingen (mehr oder weniger) mit #pragma pack aber ist das nötig? hoffe ich liege hier richtig was ich schreib... Gruß Florian
Gast wrote: > es geht nur darum kann ich den Speicher (3 Byte) die noch als overhead > da sind benutzen oder kann man die nicht mehr allozieren? Du hast erstmal per se keine 3 Bytes Overhead. Es steht dem Compiler (oder Linker) frei, Variablen mit gleichen Alignment-Anforderungen im Speicher zu packen. D. h. wenn du sowas deklarierst:
1 | uint8_t c; |
2 | uint32_t i; |
3 | uint8_t x[3]; |
dann wäre eine mögliche und sinnvolle Speicheraufteilung dafür:
1 | Byte Inhalt |
2 | ... |
3 | 192 c |
4 | 193 x[0] |
5 | 194 x[1] |
6 | 195 x[2] |
7 | 196 i |
8 | 197 i |
9 | 198 i |
10 | 199 i |
Anders ist es bei Strukturen, hier besitzt der Compiler nicht die Freiheit, die Reihenfolge zu ändern, sondern er darf lediglich dazwischen ungenutzten Platz einfügen. Das wird er in der Regel tun, wenn die Alignment-Anforderungen der Strukturelemente es erfordert. Daher ist es eine sinnvolle Idee, dass man Strukturen vom größten zum kleinsten Mitglied hin auffüllt, zuerst also alle 32-bit-Mitglieder, dann die 16-bit-Mitglieder, dann die 8-bitter. Falls ggf. dazwischen padding notwendig ist, bleibt es auf diese Weise minimal.
@Jörg Das es so optimal ausgenutztwäre, da bin ich einverstanden aber es kommt wieder drauf an was für ein system es ist... bei einem 32 bit System würde er nach dem letzten x ein Byte frei lassen (vorausgesetzt x[0] steht in den ersten 8Bit der 32) denn es ist doch für die ALU ein größerer Aufwand sich einen uint32_t aus mehreren Register "zusammen zu pfrimeln". Meinst du nicht das das der linker (macht er doch oder?) das berücksichtigt... Gruß Florian
@Gast: > also ich war eigentlich auch der Meinung das ein Byte immer 8 Bit sind > und ein char eigentlich auch... Ist ja auch sehr häufig der Fall. Außer bei DSPs und einigen ziemlich veralteten Maschinen habe ich noch nicht gehört, daß es mal anders war. Ich kenne auch kein reales Programm, das auch andere Größen berücksichtigt. > Geht nicht um ein spezielles Problem.. aber kann interessant werden bei > größeren Byte Arrays in einem 32Bit system... In einem Array stehen die Elemente immer direkt hintereinander. > man kann den compiler ja auch zwingen (mehr oder weniger) mit #pragma > pack aber ist das nötig? Das brauchst du eher für Strukturen, weil dort Padding-Bytes enthalten sein können, um korrektes Alignment für die Elemente der Struktur zu gewährleisten. Man sollte sich aber sehr gut überlegen, ob man das tut. Auf manchen Systemen sind Zugriffe mit falschem Alignment langsamer (z.B. x86), auf anderen führen sie zu einer CPU-Exception. Ein portables Datenaustauschformat ist damit auch nur bedingt machbar, da man auf eine Architektur treffen kann, die andere Alignment-Anforderungen hat. Außerdem können die Größen der Datentypen sich auch unterscheiden.
@Rolf Ah das ist doch schon mal gut das das in Arrays so ist... Mit DSP´s mach ich im Moment noch nix aber gut zu wissen... Dann werd ich #pragma pack wohl nur verwenden wenn es klar ist das das Programm nie portiert wird... vielen dank... hast du eine Idee zu der Aussage die ich an Jörg gerichtet hatte? Gruß Florian
#pragma pack gehört sowieso nicht in dieses Forum. ;-) Der GCC benutzt keine Pragmas, er macht sowas mit Attributen. __attribute__((packed)) wäre dafür also das Zutreffende.
> bei einem 32 bit System würde er nach dem letzten x ein Byte frei > lassen (vorausgesetzt x[0] steht in den ersten 8Bit der 32) In Jörgs Beispiel steht im ersten Byte c. Ansonsten hättest du recht. > denn es ist doch für die ALU ein größerer Aufwand sich einen uint32_t > aus mehreren Register "zusammen zu pfrimeln". Wie ich schon schrieb, kann es je nach CPU irgendwas von "egal" über "größerer Aufwand" bis "bricht mit CPU-Exception ab" sein. Es gibt CPUs (z.B. ARM), die auf 32-Bit-Integers nur dann zugreifen können, wenn deren Startadresse ein Vielfaches von 4 ist. > Meinst du nicht das das der linker (macht er doch oder?) das > berücksichtigt... Der Linker kümmert sich um globale Variablen und um Code. Lokale Variablen werden für gewöhnlich auf dem Stack angelegt oder in Registern gehalten. Da ist es dann Sache des Compilers. Bei dynamischem Speicher ist es Sache des Compilers und der C-Bibliothek.
@Rolf, Jörg also vielen dank... habt mir echt weitergeholfen.. aber ich werd mir glaub ich mal ein Buch über embedded c/c++ programmierung zulegen um da noch ein paar tiefere einblicke zu bekommen... Gruß Florian
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.