Die diesjährige GCC Release v15 ist raus:
https://gcc.gnu.org/gcc-15/changes.html
Per Default wird C als C23 übersetzt. Ein paar Neuerungen:
* constexpr für Objekte. Kann z.B. für Array-Größe verwendet werden.
* Direktive #embed, mit der man Binärdateien ins Programm einfügen kann.
Das ging bislang schon, war aber z.T. umständliches Binutils Gebastel.
Beispiel mit #embed:
1
#include<stdio.h>
2
#include<avr/pgmspace.h>
3
4
staticconstcharfoo_c[]PROGMEM=
5
{
6
#embed "foo.c"
7
// Append \0 so that foo_c becomes a proper C string
8
// (assuming foo.c is a text file).
9
,'\0'
10
};
11
12
intmain()
13
{
14
printf("== foo.c has %d bytes ==\n%S\n",
15
(int)sizeof(foo_c)-1,foo_c);
16
}
* bool, true und false sind Schlüsselworte. stdbool.h wird nicht mehr
gebraucht, funktioniert aber weiterhin.
* Globale asm Statements können Argumente haben.
* In Prototypen wie "int func()" ist "()" gleichbedeutend mit "(void)".
* Case Ranges (-std=c2y)
* if Deklarationen so wie in for (-std=c2y)
* Implizite Oktal-Literals sind abgeschafft. Wer wirklich 12 oktal will
schreibt also nicht mehr 012 sondern 0o12.
Auch für AVR gibt es ein paar Neuerungen:
https://gcc.gnu.org/gcc-15/changes.html#avr
* Attribute signal(num) wo num die IRQ-Nummer ist. Damit kann man
static Funktionen als ISR verwenden und auch Funktionen aus einem C++
Namespace. AVR-LibC v2.3 uterstützt das als ISR_N(num). Beispiel:
1
#include<avr/io.h>
2
3
__attribute__((signal(ADC_vect_num)))
4
staticvoidadc_isr(void)
5
{
6
// Code
7
}
8
9
#include<avr/interrupt.h>
10
11
ISR_N(INT0_vect_num)// ab AVR-LibC v2.3
12
staticvoidint0_isr(void)
13
{
14
// Code
15
}
* Unterstützung von Compact Vector Table (CVT). Auch dies erfordert
AVR-LibC v2.3.
AVR-LibC v2.3 ist noch nicht released.
News: https://github.com/avrdudes/avr-libc/blob/main/NEWS.md
(Links auf neue Header sind 404 weil die aktuelle Doku noch für v2.2
ist.)
Johann L. schrieb:> #embed "foo.c"> // Append \0 so that foo_c becomes a proper C string> // (assuming foo.c is a text file).> , '\0'> };
Und was mache ich, wenn ich keine extra \0 haben will, was bei
Binärdateien der Normalfall ist? Denn dadurch ändert sich ja die
Objektgröße.
Falk B. schrieb:> Und was mache ich, wenn ich keine extra \0 haben will, was bei> Binärdateien der Normalfall ist?
Meinst Du die Frage ernst?
Johann L. schrieb:> , '\0'
Falk B. schrieb:> Und was mache ich, wenn ich keine extra \0 haben will, was bei> Binärdateien der Normalfall ist?
Ich haette dann einfach die Zeile 9 weggelassen. Aber ich hab's nicht
ausprobiert.
Gruss
WK
Johann L. schrieb:> * Implizite Oktal-Literals sind abgeschafft. Wer wirklich 12 oktal will> schreibt also nicht mehr 012 sondern 0o12.
Vielen Dank für die Warnung. Wer war das? 0.2% meiner Quelltextzeilen
müssen geändert werden, muss das sein? Brauchen die alle kein chmod(),
open(), creat()... oder ANSI-Escapes? Funktioniert denn jetzt zum
Ausgleich wenigstens '\e' statt '033'?
Kennt der gcc 13 oder 14 diese Konstruktion schon?
Bauform B. schrieb:> Vielen Dank für die Warnung. Wer war das? 0.2% meiner Quelltextzeilen> müssen geändert werden, muss das
Du musst ja alte Quelltexte nicht mit C23 übersetzen. Wenn doch, muss es
halt C23 sein. Für den Sprachstandard kann der Compiler nichts.
Oliver
Bauform B. schrieb:> Johann L. schrieb:>> * Implizite Oktal-Literals sind abgeschafft. Wer wirklich 12 oktal will>> schreibt also nicht mehr 012 sondern 0o12.>> Vielen Dank für die Warnung. Wer war das?
WG14 Vorschlag N3193 "Obsolete implicitly octal literals" ist zum
Beispiel hier zu finden:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3193.htm>> The use of base-8 instead of base-10 by integer literals that begin>> with a zero digit is the source of frequent confusion. We propose>> marking the use of such literals as obsolete in order to encourage>> a warning that will prompt rewrites, and the introduction of a new>> prefix to explicitly mark literals that are genuinely intended to>> be in base-8.
und:
>> We propose that a new syntax is added for explicit octal constants,>> with a new prefix 0o or an alternative spelling to mark the beginning>> of a base-8 literal. The old syntax should be retained and marked as>> obsolescent to avoid breaking the meaning of existing code.
Wie es aussieht wird es eine neue Diagnostic geben, die auch deaktiviert
werden kann wenn man die alte Syntax wirklich haben will (ähnlich zu
Trigraphen).
> Kennt der gcc 13 oder 14 diese Konstruktion schon?
Das hängt weniger am Compiler als an der C-Version, welche noch nicht
released ist. C2y wird wohl C26 oder C27 werden. In C23 ist es als
Erweiterung drin, aber erst ab GCC v15:
Johann L. schrieb:> * Implizite Oktal-Literals sind abgeschafft. Wer wirklich 12 oktal will> schreibt also nicht mehr 012 sondern 0o12.
Die Änderung bezüglich der oktalen integer literals ist in C2y, nicht
C23. Und auch in C2y ist die Variante mit führender 0 nicht
"abgeschafft", sondern nur "obsolete".
Hmmm schrieb:>> Und was mache ich, wenn ich keine extra \0 haben will, was bei>> Binärdateien der Normalfall ist?>> Meinst Du die Frage ernst?>> Johann L. schrieb:>> , '\0'
Ach ich Depp, ich hab's falsch verstanden! War zu warm heute!
Johann L. schrieb:> Die diesjährige GCC Release v15 ist raus:> https://gcc.gnu.org/gcc-15/changes.html
Vielen Dank!
Habe gerade paar meiner Projekte damit und aktueller avr-libc (git)
durchgebaut. Generierter code scheint, bei mir, mit dem gcc-15.1
deutlich kleiner zu sein als gcc-14.2. An gcc-13.1 kommt er allerdings
nicht heran.
Trotzdem, vielen Dank noch mal fuer den unglaublichen Einsatz!
Wie wird uebrigens das hier funktionieren:
> * Unterstützung von Compact Vector Table (CVT). Auch dies erfordert> AVR-LibC v2.3.
In den neuen gcc/ld manpages habe ich nichts dazu gefunden. Wird es
automatisch passieren, oder wird man sich dazu linker-command-files
selber stricken muessen?
-Foka
Foka M. schrieb:> Generierter code scheint, bei mir, mit dem gcc-15.1 deutlich kleiner> zu sein als gcc-14.2. An gcc-13.1 kommt er allerdings nicht heran.
Da wäre interessant zu sehen, wo es da hakt (also Testfall, Optionen
etc.)
> Wie wird uebrigens das hier funktionieren:>> * Unterstützung von Compact Vector Table (CVT). Auch dies erfordert>> AVR-LibC v2.3.> In den neuen gcc/ld manpages habe ich nichts dazu gefunden.https://gcc.gnu.org/onlinedocs/gcc-15.1.0/gcc/AVR-Options.html#index-mcvt
Linker und Linkerscript sind unverändert.
1) libc configure stellt fest, welche Devices CVT können.
2) Für entsprechende Devices gibt es eine neue Build-Variante
crt<mcu>-cvt.o des Startup-Codes, der ja die Vectab mitbringt.
3) Welcher Startup-Code gelinkt wird entscheidet der Compiler anhand von
-mcvt: crt<mcu>.o oder crt<mcu>-cvt.o.
4) crt<mcu>-cvt.o referenziert Code, der CVT aktiviert (in .init3). Man
braucht CVT also nicht händisch zu aktivieren.
https://github.com/avrdudes/avr-libc/blob/main/libc/misc/init_cvt.S
Falls man CVT selbst aktivieren möchte, dann definiert man Symbol
__init_cvt so dass der Code nicht mehr aus der Devicelib gezogen wird.
crt<mcu>-cvt.o kann man natürlich auch mit älteren GCC Versionen
verwenden, hat dann aber nicht den Comfort von -mcvt.
Johann L. schrieb:> Foka M. schrieb:>> Generierter code scheint, bei mir, mit dem gcc-15.1 deutlich kleiner>> zu sein als gcc-14.2. An gcc-13.1 kommt er allerdings nicht heran.>> Da wäre interessant zu sehen, wo es da hakt (also Testfall, Optionen> etc.)
Ich versuche mal am kommenden langen WoE etwas mehr Inhalte zusammen zu
bekommen.
Compiler wird aufgerufen mit (nur ein Beispiel):
Ich mache vorwiegend C++ und bin gerade auf C++20 festgenagelt. Die
Unterschiede koennten also auch hieraus entstehen. Auch wenn der gcc-13
schon so ziemlich "feature complete" gewesen ist.
>> Wie wird uebrigens das hier funktionieren:>>> * Unterstützung von Compact Vector Table (CVT). Auch dies erfordert>>> AVR-LibC v2.3.>> In den neuen gcc/ld manpages habe ich nichts dazu gefunden.>> https://gcc.gnu.org/onlinedocs/gcc-15.1.0/gcc/AVR-Options.html#index-mcvt>
Oh, richtig. Habe ich in der manpage echt uebersehen.
Danke fuer die Erklaerung. Das WoE wird echt zu kurz ;-)
-Foka
Mit LTO genügt zum Nachvollziehen nicht mehr das Präcompilat eines
Moduls (z.B. mit -save-temps), weil *.o nur LTO-Bytecode enthält.
(-ffat-lto-objects hilft auch nix, weil nicht-LTO Code zur lto Time
verworfen wird).
Mit LTO braucht man also (die Präcompilate) alle(r) Module, um was
nachzuvollziehen. Evtl lässt sich mit -fno-lto eingrenzen, wo der
Codezuwachs herhommt. Wenn er nur mit -flto passiert ist es ein Indiz
dafür, dass sich was beim IPA geändert hat (Inlining, Cloning,
LTO-Partitioning, etc.).
>> Mit LTO genügt zum Nachvollziehen nicht mehr das Präcompilat eines> Moduls (z.B. mit -save-temps), weil *.o nur LTO-Bytecode enthält.> (-ffat-lto-objects hilft auch nix, weil nicht-LTO Code zur lto Time> verworfen wird).
Ich habe jetzt das gleiche ohne lto gemacht.
Geiches Projekt, gleiche compile optionen, in beiden Faellen ohne lto.
gcc-13.1:
1
Sections:
2
Idx Name Size VMA LMA File off Algn
3
0 .data 00000050 00800100 00001b0c 00001bc0 2**0
4
CONTENTS, ALLOC, LOAD, READONLY, DATA
5
1 .text 00001b0c 00000000 00000000 000000b4 2**1
6
CONTENTS, ALLOC, LOAD, READONLY, CODE
7
2 .bss 00000091 00800150 00800150 00001c10 2**0
gcc-15.1:
1
Sections:
2
Idx Name Size VMA LMA File off Algn
3
0 .data 00000050 00800100 00001b7e 00001c32 2**0
4
CONTENTS, ALLOC, LOAD, READONLY, DATA
5
1 .text 00001b7e 00000000 00000000 000000b4 2**1
6
CONTENTS, ALLOC, LOAD, READONLY, CODE
7
2 .bss 00000091 00800150 00800150 00001c82 2**0
Das sind, bei ca. 7kB in .text, 114Byte Unterschied zu Gunsten des
gcc-13.1.
Wie gesagt, ich werde mir am WoE die einzelnen Objekte ansehen, und
melde mich wieder falls ich etwas greifbareres habe.
-Foka
Johann L. schrieb:> * Implizite Oktal-Literals sind abgeschafft. Wer wirklich 12 oktal will> schreibt also nicht mehr 012 sondern 0o12.
Hmm, dann kann man jetzt endlich die 0 in dezimal schreiben. 😀
Rolf M. schrieb:> Johann L. schrieb:>> Wer wirklich 12 oktal will schreibt also nicht mehr 012 sondern 0o12.>> Hmm, dann kann man jetzt endlich die 0 in dezimal schreiben. 😀
Nicht mal das. N3193:
>> Zero remains a traditional octal constant
Da oktal in MISRA absolut verboten ist, darf man also immer noch nicht
"x = 0;" schreiben sondern muss weiterhin "x = 1-1;" o.ä.
Johann L. schrieb:> Da oktal in MISRA absolut verboten ist, darf man also immer noch nicht> "x = 0;" schreiben
Prust! Aber man kann jetzt immerhin "x = 0815;" schreiben. :-)
>>>> Mit LTO genügt zum Nachvollziehen nicht mehr das Präcompilat eines>> Moduls (z.B. mit -save-temps), weil *.o nur LTO-Bytecode enthält.>> (-ffat-lto-objects hilft auch nix, weil nicht-LTO Code zur lto Time>> verworfen wird).>> Wie gesagt, ich werde mir am WoE die einzelnen Objekte ansehen, und> melde mich wieder falls ich etwas greifbareres habe.>
Ich habe jetzt mal paar Codestellen die gcc-15.1 dicker macht genauer
angesehen. Zum einen muss ich zu geben, dass ich die gcc-13.1 und 15.1
tool-chains mit verschiedenen avr-libc Versionen gebaut habe.
Dummerweise beide direkt auf dem, damaligen, git-master basierend. Dh.
um wirklich fundierte Vergleiche zu bekommen muesste ich beide compiler
mit der gleichen avr-libc verwenden.
Mir fiel jedoch auf, dass der gcc-15.1 sich mehr um den stack pointer
'kuemmert' und dazu neigt prologue/epilogue fetter zu machen. Hier mal
eine kleine Funktion die zwei bytes auf SPI schreibt. Eigentlich sollte
es nur CS-ziehen, zwei mal `txRaw` (schreibt einen byte und wartet auf
fertig) aufrufen und dann wieder CS los lassen.
Beim gcc-13.1 sieht es so aus ('//' sind meine kommentare):
In `.Loc.16` ist eine sub-routine die den SREG rettet, interrupts
stoppt, stack pointer runter schiebt, und dann den SREG wieder zurueck
holt (gcc-15.1):
1
00001ad0 <.Loc.16>:
2
1ad0: aa 81 ldd r26, Y+2 ; 0x02
3
1ad2: b9 81 ldd r27, Y+1 ; 0x01
4
1ad4: ce 0f add r28, r30
5
1ad6: d1 1d adc r29, r1
6
1ad8: 0f b6 in r0, 0x3f ; 63
7
1ada: f8 94 cli
8
1adc: de bf out 0x3e, r29 ; 62
9
1ade: 0f be out 0x3f, r0 ; 63
10
1ae0: cd bf out 0x3d, r28 ; 61
11
1ae2: ed 01 movw r28, r26
12
1ae4: 08 95 ret
Klingt plausiebel. Aber ich frage mich, warum der gcc-13.1 das nicht
macht. Sind im neuen GCC vielleicht irgendwelche stack pointer
Schutzmechanismen eingebaut worden die jetzt mehr speicher verbrauchen?
Der gcc-13.1 schiebt den stack pointer natuerlich auch immer wieder
herum. Aber vor allem dann, wenn eine groessere sub-routine (oder
mehrere davon) aufgerufen wird. Ich habe kaum Stellen gesehen an den es
so aufwaendig gemacht wird, obwohl die sub-routine wirklich so banal ist
wie mein `txRaw` oben.
Falls es etwas bringt, kann ich den generierten code fuer die kleine
`txRaw` auch posten.
Ich habe noch paar andere Stellen gefunden, an den der gcc-15.1 sich dem
stack pointer mehr zuwendet. Es ist etwas weniger aufwaendig wie oben
und ist vollstaendig, ohne 'jump', in den prologue der Funktion
eingebettet. Allerdings macht an der gleichen Stellen der gcc-13.1
nichts weiter als nur den Stackpointer zu speichern, was viel weniger
aufwaendig und damit kuerzer ist.
Hier ein Auszug aus einer etwas groesseren Funktion. Nur der prologue.
gcc-13.1:
c70: a3 85 ldd r26, Z+11 ; 0x0b // ab hier alles wieder gleich
22
c72: b4 85 ldd r27, Z+12 ; 0x0c
Ist es moeglich dem gcc-15.1 etwas schlankere Funktionsaufrufe
beizubringen? Ich habe das Gefuel, dass ich, zumindest in meinem Code,
einiges sparen koennte.
-Foka
Jörg W. schrieb:> Johann L. schrieb:>> Da oktal in MISRA absolut verboten ist, darf man also immer noch nicht>> "x = 0;" schreiben>> Prust! Aber man kann jetzt immerhin "x = 0815;" schreiben. :-)
0815 ist weiterhin eine oktale Ganzzahl. Ab C2y in einer dann
veralteten, aber weiterhin unterstützten Schreibweise.
Foka M. schrieb:> Ist es moeglich dem gcc-15.1 etwas schlankere Funktionsaufrufe> beizubringen?
Bestimmt. Wie überall bei open source gilt: einfach machen...
Ob sich überhaupt jemand sich gross um den avr-g++ kümmert, keine
Ahnung. Der hat ja mit dem hier (implizit) besprochenen C-Compiler
nichts zu tun.
Oliver
Foka M. schrieb:> Zum einen muss ich zu geben, dass ich die gcc-13.1 und 15.1> tool-chains mit verschiedenen avr-libc Versionen gebaut habe.
Spielt auf der Ebene keine Rolle.
> In `.Loc.16` ist eine sub-routine die den SREG rettet, interrupts> stoppt, stack pointer runter schiebt, und dann den SREG wieder> zurueck holt (gcc-15.1):
Das ist __epilogue_restores
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/config/avr/lib1funcs.S;h=dfe99b1ea06f5b45e0a19942c42fe92f46e497ac;hb=HEAD#l2241
das Gegenstück zu __prologue_saves
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/config/avr/lib1funcs.S;h=dfe99b1ea06f5b45e0a19942c42fe92f46e497ac;hb=HEAD#l2188
Beide können verwendet werden wenn -mcall-prologues an ist.
> Aber ich frage mich, warum der gcc-13.1 das nicht macht.
Weil, wie du bereitst feststelltest, v15 mehr Stack beansprucht.
> Falls es etwas bringt, kann ich den generierten code fuer die kleine> `txRaw` auch posten.
Den generierten Code seh ich ja. Bestenfalls könnte man mit dem
Präcompilat (*.ii von -save-temps) was anfangen.
> Ist es moeglich dem gcc-15.1 etwas schlankere Funktionsaufrufe> beizubringen?
Da es sich um den Register-Allokator handelt wäre eine Änderung
hochgradig nichttrivial und würde alle Targets betreffen, also nicht nur
AVR.
Mit C vs. C++ hat das überigens nichts zu tun. Die > 300 Passes nach dem
Frontend sind für C und C++ die selben.
Foka M. schrieb:> Ist es moeglich dem gcc-15.1 etwas schlankere Funktionsaufrufe> beizubringen?
An den Funktionsaufrufen selbst liegt es ja nicht, es sei denn die
Funktion(en) wurden gecloned.
Vielmehr scheint es um die Sicherung von Werten über Funktionsaufrufe
hinweg zu gehen. Und da könnte -fno-caller-saves helfen.
avr-gcc (und also auch avr-g++) verwenden noch den alten lokalen
Registerallokator. Das AVR Backend befindet sich noch in der Umstellung.
Der neue Allokator ist noch nicht aktiviert; v15 verwendet noch den
alten Allokator.
Johann L. schrieb:> Vielmehr scheint es um die Sicherung von Werten über Funktionsaufrufe> hinweg zu gehen. Und da könnte -fno-caller-saves helfen.>> avr-gcc (und also auch avr-g++) verwenden noch den alten lokalen> Registerallokator. Das AVR Backend befindet sich noch in der Umstellung.> Der neue Allokator ist noch nicht aktiviert; v15 verwendet noch den> alten Allokator.
Habe gerade `-fno-caller-saves` ausprobiert. Leider bringt es in meinem
Fall nichts (keine Aenderung in der code-Groesse).
Aber es ist gut zu hoeren, dass es an der Stelle noch Potential
vorhanden ist und der Registerallokator vielleicht noch optimiert wird.
-Foka
avr-gcc 15.1.0 ist auf Godbolt.org für Experimente verfügbar.
https://godbolt.org/z/YT4b93qM6
Auf https://blog.zakkemble.net/avr-gcc-builds/ ist ein Script zur
Kompilation der Toolchain unter Linux downloadbar.
Die Links zu den aktuellen Quellen und Werkzeugen sind zu modifizieren.
https://ftp.gnu.org/gnu/ ..
Eine Arbeitsversion der avr-libc findet sich unter
https://github.com/avrdudes/avr-libc/blob/main/NEWS.md
Im Microchip Studio7 kann im "Solution Explorer | advanced | Link
flavour configuration" die Toolchain für AVR 8-Bit cpp-language und
AVR-8Bit c-language eingetragen und anschliessend für ein Projekt
ausgewählt werden.
Im Anhang ein modifiziertes ZAK-Script.
Unter Linux Mint 22.1 Xia base: Ubuntu 24.04 noble:
Done in 3178 seconds -
Toolchains are in /media/ab/Linux-HDD/avr-toolchain____/
Veit D. schrieb:> komisch, da fragt jemand nach Toolchains, bekommt alles auf dem> Silbertablett und reagiert nicht einmal.
Vielen Dank für den Link/Silbertablett - funktioniert soweit, bis auf
einen Bug der auch schon in v14 steckte, in v13 gibt es den Error nicht.
Ich bin gerade nicht Echtzeit fähig, mein Hund ist krank ...
Bug?!
1
conststruct{char*copyright,calibration;}e3={"LCQ V1.42 by XYZ","Calibration"};->syntaxerror
2
conststruct{char*copyright;char*calibration;}e3={"LCQ V1.42 by XYZ","Calibration"};->ok
Es hilft halt nichts, wenn du "char* foo" schreibst statt "char *foo" –
der Stern, der aus "char" einen Zeiger "pointer to char" macht, gehört
nicht zum Typ, sondern zum damit deklarierten "member".
Wenn du schreibst
1
conststruct{char*copyright,*calibration;}e3={"LCQ V1.42 by XYZ","Calibration"};
dann macht der Code das, was du dir vorstellst.
Offensichtlicher wäre es natürlich, auch den ersten Stern nach rechts zu
rücken:
1
conststruct{char*copyright,*calibration;}e3={"LCQ V1.42 by XYZ","Calibration"};
Wenn du für den Zeiger lieber einen Typnamen hättest, dann:
1
typedefchar*pchar;
2
conststruct{pcharcopyright,calibration;}e3={"LCQ V1.42 by XYZ","Calibration"};
Jörg W. schrieb:> Es hilft halt nichts, wenn du "char* foo" schreibst statt "char *foo" –> der Stern, der aus "char" einen Zeiger "pointer to char" macht, gehört> nicht zum Typ, sondern zum damit deklarierten "member".
Naja, er ist Teil des Typs. Aber ja, in C war es ursprünglich so
gedacht, dass er stattdessen auf der Seite des Namens steht, damit es
der Dereferenzierung des Zeigers mehr ähnelt.
> Offensichtlicher wäre es natürlich, auch den ersten Stern nach rechts zu> rücken:> const struct {char *copyright, *calibration;} e3 = {"LCQ V1.42 by> XYZ","Calibration"};
Oder einfach das Problem ganz zu umgehen, indem man die Members getrennt
deklariert:
1
conststruct{char*copyright;char*calibration;}e3={"LCQ V1.42 by
>conststruct{char*copyright,calibration;}e3={"LCQ V1.42 by
2
> XYZ","Calibration"};->syntaxerror
3
>conststruct{char*copyright;char*calibration;}e3={"LCQ V1.42 by
4
> XYZ","Calibration"};->ok
5
>
Das ist das Problem wenn man denkt alle Variablen auf eine Zeile
quetschen zu wollen um die Angabe vom Datentyp einsparen zu wollen.
Wenn man den fehlerhaften Syntax umformatiert in der Ansicht/Lesbarkeit,
sieht man sehr schnell das etwas fehlt bzw. Komma/Semikolonfehler
enthalten ist. Gerade beim Zeiger schlägt vermeintlich immer fehl, weil
sich der "Stern" immer nur auf die erste Variable bezieht. Für die
nachfolgende bleibt nur char übrig.
1
conststruct{
2
char*copyright,
3
calibration;
4
}e3={
5
"LCQ V1.42 by XYZ","Calibration"
6
};
Das wäre vielleicht einleuchtender wie das gemeint ist, das für
calibration nur char übrig bleibt. Wie gesagt, ich halte solche
Einsparmaßnahmen grundlegend für unsinnig.
1
conststruct{
2
char*copyright,
3
calibration;
4
}e3={
5
"LCQ V1.42 by XYZ","Calibration"
6
};
Deswegen bin ich kein Freund von vermeintlichen Abkürzungen. Außer ich
habe gleichartige Funktionen o.ä, die in Tabellenform besser erkennbar
sind. Den Datentyp spare ich nie ein.
conststruct{pchar_tcopyright,calibration;}e3={"LCQ V1.42 by XYZ","Calibration"};
ist der Fehler weg.
Schön ist das trotzdem nicht. Code "kompakt" schreiben zu wollen, spart
zwar Textzeilen, macht aber exakt gar nichts übersichtlicher.
Bekommt man Geld zurück, wenn man weniger Zeichen für den Quelltext
verbraucht?
Für den Compiler macht es exakt absolut überhaupt gar keinen Unterschied
aus, wenn man statt des Krampfes da oben schreibt:
Harald K. schrieb:> Der Fehler liegt hier in der Annahme, daß der * zum Typ und nicht zum> Elementnamen gehört.Jörg W. schrieb:> Wenn du schreibstconst struct {char* copyright, *calibration;} e3 => {"LCQ V1.42 by XYZ","Calibration"};> dann macht der Code das, was du dir vorstellst.>> Offensichtlicher wäre es natürlich, auch den ersten Stern nach rechts zu> rücken:> const struct {char *copyright, *calibration;} e3 = {"LCQ V1.42 by> XYZ","Calibration"};
Das hat mich jetzt sehr überrascht und zu 99% (100% wenn das aus der
aktuellen C Specification ableitbar bzw. stringent folgt) überzeugt.
Hat irgendwer einen link dazu?
Ich war immer *rechts orientiert ... und hatte jetzt angefangen davon
abzugehen, weil ich irgendwo aufgeschnappt (und viele Quellen es auch
praktisch so halten) sowie es auch logisch erscheint, dass
char*/int*/... ein daten type ist.
Die gcc Fehlermeldung ist dann auch verständlich und eindeutig. Also
mache ich jetzt wieder eine Rolle rückwärts mit *rechts, weils der
aktuelle Compiler es so will und hege 1% Zweifel ... allerdings wenn man
beachtet, dass der * dereferenziert passt es, ABER in C gibt es mehrfach
mehrfach Bedeutung von Token.
Daraus folgt, dass gcc v13.x (und davor) den Bug trägt, weil es da ohne
Fehlermeldung zwei und nicht ein pointer und char sind.
Apollo M. schrieb:> Daraus folgt, dass gcc v13.x (und davor) den Bug trägt, weil es da ohne> Fehlermeldung zwei und nicht ein pointer und char sind.
Nö, war auch dort schon nicht anders:
1
$ gcc -v
2
Using built-in specs.
3
…
4
Thread model: posix
5
gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)
6
$ gcc -c bug.c
7
bug.c:1:71: warning: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
Veit D. schrieb:> Wie gesagt, ich halte solche> Einsparmaßnahmen grundlegend für unsinnig.
Widerspruch, weil denkbar eine Frage von persönlicher Perspektive ...
weitere Beispiele zum diskutieren :-)
Jörg W. schrieb:> gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)
bei gcc Wx-x64 v8.x, 10.x, 13.x compilierbar ohne error, allerdings habe
ich die warnings nicht beachtet, weil zu viele :-)
Apollo M. schrieb:> Daraus folgt, dass gcc v13.x (und davor) den Bug trägt, weil es da ohne> Fehlermeldung zwei und nicht ein pointer und char sind.
Kann ich nicht bestätogen. Eine adäquate Fehlermeldung (keine Warning)
sehe ich mit GCC v3.4, v5.4, v8, v12, v13, v14, v15.
Damit der Code compiliert kann man als C++ übersetzen zusammen mit
-fpermissive, also explizit kaputten[tm] Code erlauben:
Ohne -fpermissive:
Apollo M. schrieb:> Das hat mich jetzt sehr überrascht und zu 99% (100% wenn das aus der> aktuellen C Specification ableitbar bzw. stringent folgt) überzeugt.> Hat irgendwer einen link dazu?
Ganz simpler Test:
Apollo M. schrieb:> Veit D. schrieb:>> Wie gesagt, ich halte solche>> Einsparmaßnahmen grundlegend für unsinnig.>> Widerspruch, weil denkbar eine Frage von persönlicher Perspektive ...> weitere Beispiele zum diskutieren :-)>>
1
>//der ersten Variante gebe ich den Vorzug
2
>while(1)continue;while(1);while(1){};
3
>while(x=y,x);while(x=y);x=y;while(x)
4
>
Das kann man so schreiben wenn es sonst niemand liest. :-) Es wird auch
für dich Jahre später schwer lesbar sein.
Verstehe mich nicht falsch. Du kannst schreiben wie du das möchtest. Nur
wenn der Compiler meckert, spätestens dann sollte man seine Zeilen
überprüfen.
Ein Bjarne Stroustrup und Ulrich Breymann schreiben in ihren Büchern
auch
1
int* ip
und nicht "durchgehend"
1
int*ip
Obwohl U. Breymann in seinem Text dazu folgendes richtig beschreibt.
1
Die Variable ip ist vom Typ »Zeiger auf int«. Der Stern * bezieht sich also nur auf den direkt folgenden Namen.
Und paar Zeilen darüber auf gleicher Seite schreibt er es in der Form
1
int*ip{&i}
Das heißt wie schon gesagt bei Schreibweisen mit Mehrfachaufzählung wie
1
int*ip,mac
wird es gefährlich, weil mac kein Zeiger mehr hat, sondern nur den
Datentyp int.
Wenn man jeder Deklaration eine eigene Zeile gönnt, dann ist es
praktisch egal wie man es schreibt. Dann ist es immer sofort
ersichtlich.
Apollo M. schrieb:> Daraus folgt, dass gcc v13.x (und davor) den Bug trägt, weil es da ohne> Fehlermeldung zwei und nicht ein pointer und char sind.
Was ich dazu noch sagen möchte. Unabhängig davon ob das bei dir
kompilierte und nun nicht mehr o.ä. Generell wird jede neue
Compilerversion strenger. Wirft also mehr Warnungen/Fehler wie die
Version davor. Das sollte man dankbar aufnehmen um Probleme im Code zu
erkennen um damit schwerwiegende Fehler im Vorfeld vermeiden zu können.
Siehe die Fehlermeldung also nicht als Bug sondern als Hilfe.
Veit D. schrieb:> Was ich dazu noch sagen möchte.
Da bin ich bei dir und bin froh, dass ich den "angeblichen Bug" erwähnt
habe, weil ich dazu lernen konnte.
Apollo M. schrieb:> Harald K. schrieb:>> Ganz simpler Test:>> Überzeugt trotzdem und Grund genug die 1% Zweifel jetzt an der Garderobe> abzugeben!
Ein Test ersetzt aber keine Spezifikation.
Im C99 Standard: Im Abschnitt 6.7.5 Declarators ist der Aufbau von
Deklaratoren beschrieben, woraus sich die Semantik der diskutierten
Deklaration ergibt. Das ganze ist im Stil einer kontextfreien Grammatik
formuliert, damit alle möglichen Fälle (das sind unendlich viele)
abgedeckt sind.
Johann L. schrieb:> Ein Test ersetzt aber keine Spezifikation.
Das ist richtig; nur ist offenkundig die Spezfikation, um die es hier
letzlich geht, schon sehr, sehr lange elementarer Sprachbestandteil. Das
war nämlich schon im ungeliebten K&R-C, also dem nicht standardisierten
Urschleim vor C89 (damals "ANSI-C" genannt) so.
Foka M. schrieb:> Habe gerade paar meiner Projekte damit und aktueller avr-libc (git)> durchgebaut. Generierter code scheint, bei mir, mit dem gcc-15.1> deutlich kleiner zu sein als gcc-14.2. An gcc-13.1 kommt er allerdings> nicht heran.
Ein Grund könnte der alte lokale Register-Allokator sein (Reload). GCC
hat 2 solcher lokaler Allokatoren, und das alte Reload ist bei fast
allen Targets schon durch das neue LRA ersetzt -- nicht aber für AVRhttps://gcc.gnu.org/PR113934
weil es noch einen Fall gibt, wo LRA falschen Code erzeugt:
https://gcc.gnu.org/PR118591
Aus diesem Grunde ist -mlra im avr-gxx noch deaktiviert (und nicht
dokumentiert, weil die Option ja spätestens mit Entfernung von Reload
wieder entfällt).
Hier ein Beispiel, wo die Codegröße von v13 zu v15 ansteigt. (Reload
wird natürlich nicht mehr supprted, zumindest nicht was die Qualität des
erzeugten Codes angeht.)