Forum: PC-Programmierung GCC: Konstant oder nicht konstant?


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

ich habe folgenden Quelltext-Schnipsel:
1
    const uint32_t nOverflowPerPulse = 2;
2
    static_assert( nOverflowPerPulse >= 2 , " Invalid configuration ");

Der GCC 5.1.0 baut mir den Quelltext, der diesen Schnipsel enthält, 
anstandslos, wenn mit -O1 gebaut ist. Wenn mit -O0 gebaut wird, bricht 
die Kompilierung ab mit:
1
error: expression in static assertion is not constant
2
     static_assert( nOverflowPerPulse >= 2 , " Invalid configuration ");

ändere ich den Schnipsel:
1
    const uint32_t nOverflowPerPulse = 2;
2
    assert( nOverflowPerPulse >= 2 );

moniert der Der ARM-GCC 5.4.1 zu Recht:
"warning: statement with no effect [-Wunused-value]|"

Was ich nicht verstehe:

 a) Wann entscheidet der Compiler, wann was konstant ist? Und

 b) Wie bekomme ich den/die Compiler in allen Optimierungsstufen 
zufrieden?

von (prx) A. K. (prx)


Lesenswert?

C "const" Variablen sind nicht äquivalent zu lexikalischen Konstanten, 
sondern sind konstante Variablen (ja, komischer Name).

In C++ ist das anders.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Walter T. schrieb:
> a) Wann entscheidet der Compiler, wann was konstant ist?

In C sind nur Literale konstant. Dass es bei -O2 funktioniert, ist hier 
nur Zufall (dank constant propagation).

Walter T. schrieb:
> b) Wie bekomme ich den/die Compiler in allen Optimierungsstufen
> zufrieden?
In C:
1
const uint32_t nOverflowPerPulse = 2;
2
assert( nOverflowPerPulse >= 2 );
3
(void) nOverflowPerPulse;
In C++:
1
constexpr uint32_t nOverflowPerPulse = 2;
2
static_assert (nOverflowPerPulse >= 2, "Invalid configuration");
"constexpr" ist in C++ konstant und Compile-Time-bekannt, d.h. der 
Compiler kann es beim kompilieren prüfen.

von Oliver S. (oliverso)


Lesenswert?

Welche C++-Sprachstandards verwendest du denn?

Oliver

von wolpino (Gast)


Lesenswert?

Das C++11-Schlüsselwort 'constexpr' sollte in allen Fällen 
funktionieren.
1
    #include <cstdint> 
2
    constexpr uint32_t nOverflowPerPulse = 2;
3
    static_assert( nOverflowPerPulse >= 2 , " Invalid configuration ");

Zum Ausprobieren kleiner Codeschnipsel gibt es den genialen 
Compiler-Explorer von Godbolt: https://godbolt.org/
Man tippt/kopiert einen Quelltext-Schnipsel direkt im Browser ein und 
der spuckt sofort den kommentierten ASM-Code auf der Web-Seite wieder 
aus oder meckert, wenn er nicht kompiliert werden kann. Man kann die 
verschiedensten Compiler auswählen und mit ihren Optionen herumspielen.

von DPA (Gast)


Lesenswert?

1
enum { nOverflowPerPulse = 2 };
2
static_assert( nOverflowPerPulse >= 2, "Invalid configuration" );

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Walter T. schrieb:

>  b) Wie bekomme ich den/die Compiler in allen Optimierungsstufen
> zufrieden?

In dem Du Ihm sagst, dass es ein `constexpr` ist. Dann kann er die 
Optimierung oben nicht auslassen.

von Oliver S. (oliverso)


Lesenswert?

Torsten R. schrieb:
> In dem Du Ihm sagst, dass es ein `constexpr` ist.

Was in C++ nicht nötig ist (da kompiliert der gcc das in allen 
Optimierungsstufen völlig klaglos), und in C nicht möglich.

Und auch wenn Walter das kleine Detail, in was er nun programmiert, uns 
nicht mitteilen möchte, wird es doch C sein.

Das der gcc das in C in den höheren Optimierungsstufen frisst, ist ... 
seltsam. Denn wie schon geschrieben wurde, ist ein const in C kein 
integral const.

Oliver

von DPA (Gast)


Lesenswert?

Oliver S. schrieb:
> und in C nicht möglich.

Deshalb mein Beispiel mit enum, das geht in C.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Walter T. schrieb:
> Der GCC 5.1.0 baut mir den Quelltext, der diesen Schnipsel enthält,
> anstandslos, wenn mit -O1 gebaut ist. Wenn mit -O0 gebaut wird, bricht
> die Kompilierung ab mit:
>
> error: expression in static assertion is not constant
>      static_assert( nOverflowPerPulse >= 2 , " Invalid configuration ");

Das ist seltsam.

Offiziell sollte die Fehlermeldung – unabhängig vom Optimierungslevel –
in C immer kommen und in C++ überhaupt nicht. Möglicherweise ist das ein
Bug in 5.1.0. Der bei mir installierte 8.2.1 verhält sich diesbezüglich
korrekt.

von Oliver S. (oliverso)


Lesenswert?

Auf godbolt zeigt auch ein gcc 8.3 das gleiche Verhalten wie der 5.1 
(und auch Versionen dazwischen).

Oliver

von Walter T. (nicolas)


Lesenswert?

Oliver S. schrieb:
> Auf godbolt zeigt auch ein gcc 8.3 das gleiche Verhalten wie der 5.1

https://godbolt.org/z/l7550g

Bei mir zeigt der GCC in beiden Versionen das optimierungsabhängige 
Verhalten.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Walter T. schrieb:
> Bei mir zeigt der GCC in beiden Versionen das optimierungsabhängige
> Verhalten.

Ja, jetzt kann ich das Problem auch beim 8.2.1 reproduzieren. Zuvor
hatte ich die Definition von nOverflowPerPulse und das static_assert
außerhalb von main, dann erscheint die Fehlermeldung immer.


Edit:

Ich schätze, diese etwas seltsame Verhalten ist aus folgendem Grund
korrekt:

Nach ISO muss das erste Argument von _Static_assert (und damit auch von
static_assert aus assert.h) eine constant-expression sein:

1
_Static_assert ( constant-expression , string-literal ) ;

Eine mit const deklarierte Variable sind normalerweise keine
constant-expression, darf es aber implementationsabhängig sein:

1
An implementation may accept other forms of constant expressions.

Damit ist es kein Fehler, wenn der Compiler die const-Variable in einem
static_assert zurückweist, es ist aber auch keiner, wenn er sie
akzeptiert. Man sollte sich aber beim Schreiben von portablen Code auf
letzteres nicht verlassen.

: Bearbeitet durch Moderator
von Walter T. (nicolas)


Lesenswert?

Danke, das ist einleuchtend.

von Roland F. (rhf)


Lesenswert?

Hallo,
Oliver S. schrieb:
> Denn wie schon geschrieben wurde, ist ein const in C kein
> integral const.

Kannst du das mal genauer erklären was das bedeutet?

rhf

von Jan (Gast)


Lesenswert?

Roland F. schrieb:
> Hallo,
> Oliver S. schrieb:
> Denn wie schon geschrieben wurde, ist ein const in C kein integral
> const.
>
> Kannst du das mal genauer erklären was das bedeutet?
>
> rhf

Es gibt in C keine "echten" zur Kompilierzeit konstante Variablen, mit 
denen zb Arrays deklariert werden können. Man muss #define oder eben ein 
enum nehmen.
In C++ hingegen schon.

von Daniel -. (root)


Lesenswert?

Jan schrieb:
> Roland F. schrieb:
> Hallo,
> Oliver S. schrieb:
> Denn wie schon geschrieben wurde, ist ein const in C kein integral
> const.
> Kannst du das mal genauer erklären was das bedeutet?
> rhf
>
> Es gibt in C keine "echten" zur Kompilierzeit konstante Variablen, mit
> denen zb Arrays deklariert werden können. Man muss #define oder eben ein
> enum nehmen. In C++ hingegen schon.

was es in C möglich macht, die Adressen von const Objekten zu nehmen.

von mh (Gast)


Lesenswert?

Daniel -. schrieb:
> Jan schrieb:
>> Roland F. schrieb:
>> Hallo,
>> Oliver S. schrieb:
>> Denn wie schon geschrieben wurde, ist ein const in C kein integral
>> const.
>> Kannst du das mal genauer erklären was das bedeutet?
>> rhf
>>
>> Es gibt in C keine "echten" zur Kompilierzeit konstante Variablen, mit
>> denen zb Arrays deklariert werden können. Man muss #define oder eben ein
>> enum nehmen. In C++ hingegen schon.
>
> was es in C möglich macht, die Adressen von const Objekten zu nehmen.

Was genau macht das in C möglich?

von Heiko L. (zer0)


Lesenswert?

Yalu X. schrieb:
> Man sollte sich aber beim Schreiben von portablen Code auf
> letzteres nicht verlassen.

Rant: Warum sollte man das auch? Es gibt doch allerhöchstens einen 
einzigen C99-Compiler.

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
Noch kein Account? Hier anmelden.