Ja, ich weiß, der Compiler hat immer Recht, aber in diesem Fall... sehe
ich es einfach nicht. Beim ersten Versuch (ohne default: mit allen case)
dachte ich noch, der switch deckt alle Werte des shm_type_enum ab (gcc
merkt auch, wenn nicht), also wird das Ende der Funktion nie erreicht.
Das stimmt so nicht, weil in SHM_DATA_TYPES[] ein Wert vorkommt der im
enum nicht vorkommt. Genau für solche Fälle möchte ich auch eine Warnung
sehen.
Aber mit default: sind doch wirklich alle Werte abgedeckt und trotzdem
gibt es anscheinend einen Pfad zum Ende der Funktion.
Ich sehe hier nirgends einen "'return' with no value". Vermutlich liegt
der Fehler in einer Datei, die du nicht gepostet hat. Oder du hast
Änderungen am Code vorgenommen, aber das Abspeichern vergessen.
Yalu X. schrieb:> Ich sehe hier nirgends einen "'return' with no value".
Warscheinlch braucht er ausserhhalb der switch-Klammer
ein "return (irgendwas)".
Rätselprogrammierer schrieb:> Warscheinlch braucht er ausserhhalb der switch-Klammer> ein "return (irgendwas)".
Nein, die Fehlermeldung sagt aus, dass da zwar ein 'return' steht, aber
ohne Argument. Und genau dieses argumentlose 'return' kommt in seinem
gepostenen Code gar nicht vor.
Wollte sich der Compiler (ich nehme an, GCC) über ein komplett fehlendes
'return' beschweren, würde er dies mit
"control reaches end of non-void function"
tun.
Yalu X. schrieb:
> Wollte sich der Compiler (ich nehme an, GCC) über ein komplett fehlendes> 'return' beschweren, würde er dies mit>> "control reaches end of non-void function">> tun.
In der Tat, man sollte immer das Kleingedruckte lesen. Damit muss es
wohl am exit() liegen. Aber das heißt ja, dass der gcc aus dem
((noreturn)) ein return; macht... Für den switch passt das (man braucht
kein break), aber für die Funktion ist es eben ein return with no value.
Aber ich finde, ((noreturn)) bedeutet "no return" und wie soll ohne
return etwas zurück gegeben werden? Man kann also nur aus void
Funktionen ausbrechen? In einer normalen main() funktioniert das doch
auch?
Der GCC ist ein selbst gebauter arm-none-eabi-7.0.1
Da du ja keinen kompilierbaren Code gepostet hast, habe ich meinen
eigenen zusammengebastelt, siehe Anhang. Damit funktioniert es. Daher
ist nicht nachvollziehbar, wo dein Problem liegt. Getestet mit x86_64
GCC 5.4.0, arm-none-eabi-gcc 6.3.1, sowie Clang 3.8.0.
Rück Kehrer schrieb:> Der GCC ist ein selbst gebauter arm-none-eabi-7.0.1
Aber der zeigt doch genau die Zeile und die Stelle an, wo das Problem
ist.
> Damit muss es wohl am exit() liegen. Aber das heißt ja, dass der gcc> aus dem ((noreturn)) ein return; macht...
Nein. noreturn funktioniert wie erwartet. Der Fehler ist woanders,
z.B. falsche Header o.ä.
> Aber ich finde, ((noreturn)) bedeutet "no return"
So ist es.
> Man kann also nur aus void Funktionen ausbrechen?
Nein.
Rück Kehrer schrieb:> Aber ich finde, ((noreturn)) bedeutet "no return" und wie soll ohne> return etwas zurück gegeben werden?
Die Funktion könnte in C++ implementiert sein und eine Exception werfen.
Aber das sollte nicht zu dieser Warnung führen.
Rück Kehrer schrieb:> // syslib.h> #pragma once> #include <stdarg.h>> #include <stdint.h>>> void exit (int status) _attribute_ ((noreturn));> /* gekürzt */
Nur so am Rande: Gibt es einen speziellen Grund, warum du exit() selbst
deklarierst?
Bernd K. schrieb:> Rolf M. schrieb:>> Nur so am Rande: Gibt es einen speziellen Grund, warum du exit() selbst>> deklarierst?>> Hat er das?
Ähm, ich hab doch sogar den Teil zitiert, wo er das hat.
Bernd K. schrieb:> Rolf M. schrieb:>> Nur so am Rande: Gibt es einen speziellen Grund, warum du exit() selbst>> deklarierst?>> Hat er das?
Ja, nämlich im hausbackenen syslib.h.
Standardmäßig ist die deklariert in stdlib.h. Und GCC kennt den
Prototyp ohnehin (außer bei freestanding).
Dr. Sommer schrieb:
> Da du ja keinen kompilierbaren Code gepostet hast, habe ich meinen> eigenen zusammengebastelt, siehe Anhang. Damit funktioniert es. Daher> ist nicht nachvollziehbar, wo dein Problem liegt.
Hier auch nicht mehr :( Ursprünglich war ich auf der Suche nach einer
Konstruktion für meine logischen Datentypen (Volt, Minuten,...) mit der
ich auch zuverlässig Warnungen bekomme. Und dann hab' ich mich um
diese Warnung im Kreis gedreht.
Alles um diesen switch herum ist statisch und vollständig definiert.
Also hatte ich gehofft, dass der gcc auch den Inhalt von
SHM_DATA_TYPES[] berücksichtigt. Zusammen mit der Prüfung auf die
Feldgrenze wäre das doch theoretisch möglich. Na gut, jetzt steht am
Ende der Funktion noch ein exit(), falls sich das Programm doch dahin
verlaufen sollte.
Johann L. schrieb:
> Rück Kehrer schrieb:>> Damit muss es wohl am exit() liegen. Aber das heißt ja, dass der gcc>> aus dem ((noreturn)) ein return; macht...>> Nein. noreturn funktioniert wie erwartet. Der Fehler ist woanders,> z.B. falsche Header o.ä.
Tut es und ist er. Zwischen Bildschirm und Tastatur wie meistens.
Rolf M. schrieb:
> Nur so am Rande: Gibt es einen speziellen Grund, warum du exit() selbst> deklarierst?
Johann L. schrieb:
> Und GCC kennt den Prototyp ohnehin (außer bei freestanding).
Ich möchte die Abhängigkeit von einer newlib o.ä. vermeiden (praktisch
die Steigerung von freestanding?). Die paar simplen Funktionen, die ich
brauche, sind gleich eingetippt (na gut, printf hab' ich vom ChibiOS
ausgeborgt; danke, Giovanni Di Sirio).
Dr. Sommer schrieb:
> Rück Kehrer schrieb:>> if (index >= sizeof SHM_DATA_TYPES) {> Das ist übrigens falsch, du meinst vermutlich:if (index >=> sizeof(SHM_DATA_TYPES) / sizeof(SHM_DATA_TYPES[0]))
Ja, das ist ein heikles Thema. Eigentlich hast du Recht. Aber wer
sowieso mit -Os kompiliert, schreibt auch -fshort-enums dazu. Das ist
beim cortex-m wohl auch Standard laut aapcs. Bei einer kritischen struct
schreibe ich auch gerne _Static_assert zwecks Größen-Prüfung dazu.
Deshalb hab' ich wegen der Zeile kein schlechtes Gewissen; ich finde es
so lesbarer.
Vielen Dank an alle!
Rück Kehrer schrieb:> Ja, das ist ein heikles Thema. Eigentlich hast du Recht.
Aaah, ich habe definitiv Recht!
Rück Kehrer schrieb:> Deshalb hab' ich wegen der Zeile kein schlechtes Gewissen; ich finde es> so lesbarer.
Weil man so verwirrt ist, ob du jetzt wirklich nur auf einen "normalen"
Array Überlauf prüfen möchtest oder irgendwas anderes komisches? Es hat
definitiv keinerlei Nachteil das korrekt hinzuschreiben, dann
funktioniert es immer, und dann weiß jeder was gemeint ist. Ohne Not
Code zu schreiben der nur unter ganz bestimmten Bedingungen
funktioniert, und sonst ohne jegliche Vorwarnung Unsinn macht, ist eine
ganz schlechte Angewohnheit.
Du programmierst ja in C, da musst du mit umständlichem Code leben. Wenn
du C++ nutzen würdest, könntest du es so kompakt schreiben:
Rück Kehrer schrieb:> Na gut, jetzt steht am> Ende der Funktion noch ein exit(), falls sich das Programm doch dahin> verlaufen sollte.
Obwohl die Warnung jetzt gar nicht mehr auftritt? Da wäre es doch
sinnvoller das wegzulassen, damit die Warnung eben doch kommt, falls du
was (falsch) änderst.
PS: Bei solchen Fällen könnte ggf auch __builtin_unreachable helfen,
aber das ist dann besonders hässlich.
Rück Kehrer schrieb:> Rolf M. schrieb:>> Nur so am Rande: Gibt es einen speziellen Grund, warum du exit() selbst>> deklarierst?> Johann L. schrieb:>> Und GCC kennt den Prototyp ohnehin (außer bei freestanding).> Ich möchte die Abhängigkeit von einer newlib o.ä. vermeiden (praktisch> die Steigerung von freestanding?).
exit() ist eine Standard-C-Funktion. Die existiert in jeder konformen
C-Implementation, die nicht freestanding ist.
Dr. Sommer schrieb:
> Es hat> definitiv keinerlei Nachteil das korrekt hinzuschreiben, dann> funktioniert es immer, und dann weiß jeder was gemeint ist.
Buchstabenverschwendung, Tastaturabnutzung, Stromverbrauch,... aber du
stimmst mich nachdenklich, ich möchte ja lesbare Programme schreiben.
> Rück Kehrer schrieb:>> Na gut, jetzt steht am>> Ende der Funktion noch ein exit(), falls sich das Programm doch dahin>> verlaufen sollte.> Obwohl die Warnung jetzt gar nicht mehr auftritt? Da wäre es doch> sinnvoller das wegzulassen, damit die Warnung eben doch kommt, falls du> was (falsch) änderst.
Ein Mißverständnis; der switch sollte niemals ein default label haben.
Und wenn dann kein exit() und kein return am Ende steht, gibt es die
Warnung immer noch. Normalerweise auch total berechtigt, weil ja von
draußen beliebige Werte kommen könnten, auch wenn der switch alle
enum-Werte abdeckt. Dies ist ja ein extremer Sonderfall in dem alles
komplett statisch ist.
Eine sinnvolle Warnung vom Compiler bekomme ich hier wohl nicht. Mit dem
exit() gibt es wenigstens einen definierten Laufzeitfehler. Ein return
wäre hier nur schädlich.
> PS: Bei solchen Fällen könnte ggf auch __builtin_unreachable helfen,> aber das ist dann besonders hässlich.
Das muss wirklich hässlich sein, das kannte ich noch garnicht :)
Rolf M. schrieb:
> exit() ist eine Standard-C-Funktion. Die existiert in jeder konformen> C-Implementation, die nicht freestanding ist.
willst du damit sagen, dass ich meine exit() anders nennen sollte? Die
verhält sich praktisch wie die Standard-Funktion. Man würde doch z.B.
ein eigenes printf() auch nicht umbenennen, auch wenn es nicht alle
Formate kennt?
Rück Kehrer schrieb:> Rolf M. schrieb:>> exit() ist eine Standard-C-Funktion. Die existiert in jeder konformen>> C-Implementation, die nicht freestanding ist.> willst du damit sagen, dass ich meine exit() anders nennen sollte? Die> verhält sich praktisch wie die Standard-Funktion.
Ah, mir war nicht bewusst, dass du die Funktion selbst implementiert
hast. Ich dachte, du verwendest die Standardfunktion, benutzt aber aus
irgendeinem Grund nicht den Header, in dem sie deklariert ist.
Also ich würde sie anders nennen, und wenn's "myexit()" ist oder so. Ich
finde es schon sinnvoll, erkennbar zu machen, wenn man nicht die
Originalfunktion, sondern eine selbst gestrickte verwendet, auch wenn
sie funktional gleich ist.
In C++ kann man das schön über Namespaces lösen. Gleicher Name, aber
anderer Namespace. Gibt's in C aber nicht.
Rück Kehrer schrieb:> Aber wer sowieso mit -Os kompiliert, schreibt auch -fshort-enums dazu.
Warum sollte man? -Os ist eine Option zur Codeoptimierung.
-fshort-enums ändert das Binärinterface (ABI). Ich seh jetzt nicht,
warum Optimierung Änderung des ABI implizieren sollte.
Johann L. schrieb:> Rück Kehrer schrieb:>> Aber wer sowieso mit -Os kompiliert, schreibt auch -fshort-enums dazu.>> Warum sollte man? -Os ist eine Option zur Codeoptimierung.> -fshort-enums ändert das Binärinterface (ABI). Ich seh jetzt nicht,> warum Optimierung Änderung des ABI implizieren sollte.
Man kann es natürlich so formulieren, dass es irgendwie keinen
Zusammenhang zu haben scheint. Oder eben: -Os ist ein Parameter, um
Speicher zu sparen, -fshort-enums auch. Und schon passt es zusammen. Ich
glaube aber, dass es in der Praxis wenig Programme gibt, bei denen man
mit -fshort-enums signifikant Platz sparen kann.
Rolf M. schrieb:> Ich> glaube aber, dass es in der Praxis wenig Programme gibt, bei denen man> mit -fshort-enums signifikant Platz sparen kann.
Mit -fshort-enums spart man vor allem Code/Laufzeit auf
8-Bit-Architekturen, weil alles in einem statt zwei Registern gehandhabt
werden kann.
Rolf M. schrieb:> Johann L. schrieb:>> Rück Kehrer schrieb:>>> Aber wer sowieso mit -Os kompiliert, schreibt auch -fshort-enums dazu.>>>> Warum sollte man? -Os ist eine Option zur Codeoptimierung.>> -fshort-enums ändert das Binärinterface (ABI). Ich seh jetzt nicht,>> warum Optimierung Änderung des ABI implizieren sollte.>> Man kann es natürlich so formulieren, dass es irgendwie keinen> Zusammenhang zu haben scheint. Oder eben: -Os ist ein Parameter, um> Speicher zu sparen, -fshort-enums auch.
Nein. -fshort-enums ist ein Schalter, um ein anderes ABI einzustellen.
Dass das gegebenenfalls zu kleinerem Code führt ist ein angenehmer
Nebeneffekt, mehr nicht.
Prinzipiell sind Objekte / Module, die mit unterschiedlichen
Optimierungsstufen oder -schaltern übersetzt wurden, zusammen
funktionsfähig und interoperabel.
Auf Objekte und Bibliotheken hingegen, die für unterschiedliches ABI
übersetzt wurden, trifft das i.d.R nicht zu.
Das alles ist bereits daran erkennbar, dass die GCC-Doku -Os et al. als
Optimierungsoption listet
http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
während -fshort-enums unter "Options for Code Generation Conventions"
These machine-independent options control the interface conventions used
in code generation.
http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
Johann L. schrieb:>> Man kann es natürlich so formulieren, dass es irgendwie keinen>> Zusammenhang zu haben scheint. Oder eben: -Os ist ein Parameter, um>> Speicher zu sparen, -fshort-enums auch.>> Nein. -fshort-enums ist ein Schalter, um ein anderes ABI einzustellen.
Und warum sollte man das wollen? Einfach so, um mal etwas Abwechslung zu
haben?
> Dass das gegebenenfalls zu kleinerem Code führt ist ein angenehmer> Nebeneffekt, mehr nicht.
Ich seh's genau umgekehrt. -fshort-enums ist ein Schalter für kleineren
Code (und ggf. kleinere Daten). Dass sich dadurch das ABI ändert, ist
ein unangenehmer Nebeneffekt.
> Auf Objekte und Bibliotheken hingegen, die für unterschiedliches ABI> übersetzt wurden, trifft das i.d.R nicht zu.
Das hat aber erstmal mit dem primären Zweck des Schalters nichts zu tun.
Rolf M. schrieb:
> Johann L. schrieb:>>> Man kann es natürlich so formulieren, dass es irgendwie keinen>>> Zusammenhang zu haben scheint. Oder eben: -Os ist ein Parameter, um>>> Speicher zu sparen, -fshort-enums auch.>>>> Nein. -fshort-enums ist ein Schalter, um ein anderes ABI einzustellen.>> Und warum sollte man das wollen? Einfach so, um mal etwas Abwechslung zu> haben?>>> Dass das gegebenenfalls zu kleinerem Code führt ist ein angenehmer>> Nebeneffekt, mehr nicht.>> Ich seh's genau umgekehrt. -fshort-enums ist ein Schalter für kleineren> Code (und ggf. kleinere Daten). Dass sich dadurch das ABI ändert, ist> ein unangenehmer Nebeneffekt.
Ich sehe es noch umgekehrter;) Ich schreibe jetzt zum "typedef enum" ein
"__attribute__((packed))" dazu und lasse den Schalter weg. Der gcc
produziert dann mit -fno-short-enums genauso kleine Binaries (±8 Byte
bei 60k) und das ABI wird nicht angetastet. Allerdings ist -fshort-enums
bei den cortex-m sowieso der Default, ich finde nur nicht, wo das
genau festgelegt ist.
"Using the GNU Compiler Collection (For gcc version 7.0.1)" sagt nur:
1
Chapter 4: C Implementation-Defined Behavior
2
4.9 Structures, Unions, Enumerations, and Bit-Fields
3
On some targets, `-fshort-enums' is the default;
4
this is determined by the ABI.
Im "ARM Procedure Call Standard for the ARM® Architecture" lässt ARM das
auch offen, schreibt aber:
1
7.1.3 Enumerated Types
2
Discussion
3
The definition of enumerated types in the C and C++ language standards
4
does not define a binary interface and leaves open the following
5
questions.
6
* Does the container for an enumerated type have a fixed size
7
(as expected in most OS environments) or is the size no larger than
8
needed to hold the values of the enumeration (as expected by most
Rück Kehrer schrieb:> Ich sehe es noch umgekehrter;) Ich schreibe jetzt zum "typedef enum" ein> "__attribute__((packed))" dazu und lasse den Schalter weg.
Oder du nutzt C++, wo du die Größe direkt portabel ohne
Compiler-spezifische Erweiterungen oder Flags angeben kannst:
Johann L. schrieb:> Dr. Sommer schrieb:>> Oder du nutzt C++,>> Motto: Um ein Problem in Sprache X zu lösen, verwende ich immer Sprache> Y.
Motto: Warum jedes Problem mit einem Schraubendreher angehen, wenn es
schon seit Jahrzehnten Bohrmaschinen gibt? Wir haben hier offensichtlich
Probleme, die durch C++ gelöst werden.
Johann L. schrieb:> Dr. Sommer schrieb:>> Oder du nutzt C++,>> Motto: Um ein Problem in Sprache X zu lösen, verwende ich immer Sprache> Y.
ersetze Y durch X++, eine Sprache, in der du so gut wie alles genau so
schreiben kannst, nur dass sie unter anderem das gewünschte Feature
schon mitbringt.
Dr. Sommer schrieb:> Motto: Warum jedes Problem mit einem Schraubendreher angehen, wenn es> schon seit Jahrzehnten Bohrmaschinen gibt?
Die von dir vorgeschlagene Bohrmaschine ist aber gerade mal
0,6 Jahrzehnte alt ;-)
Yalu X. schrieb:> Dr. Sommer schrieb:> Motto: Warum jedes Problem mit einem Schraubendreher angehen, wenn es> schon seit Jahrzehnten Bohrmaschinen gibt?>> Die von dir vorgeschlagene Bohrmaschine ist aber gerade mal> 0,6 Jahrzehnte alt ;-)
Immerhin! Na, der Spruch bezog sich mehr auf C++ im Allgemeinen. Auch
das alte C++ enthält nützliche Dinge...