GCC: Konstant oder nicht konstant?

OP #5775538
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?
Persönliche Seite #5775552
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.
Gast #5775565
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.
#5775585
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
Moderator #5775619
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.
Moderator #5775683
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.
Gast #5779238
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.
#5779921
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.
Gast #5780004
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren