Forum: Compiler & IDEs Der gcc soll bitte mehr Fehler finden


von Bauform B. (bauformb)


Lesenswert?

Wilhelm M. schrieb im
Beitrag "Re: avr-gcc: direkter Register Zugriff vs structure-mapping und fehlende Optimierung?"

> In C++ benutze ich schon immer ein structure-mapping mit
> eingenen Register-Typen, so dass auch nur die richtigen
> Flags für die Register benutzt werden können, ansonsten
> Compile-Zeit-Fehler

Könnte man das in C ohne ++ auch haben? Etwas ähnliches erreicht man 
wohl mit Bitfeldern in der struct, aber das ist umständlich, wenn man 
mehrere Bits gleichzeitig setzen muss.

von Ein T. (ein_typ)


Lesenswert?

Bauform B. schrieb:
> Wilhelm M. schrieb im
> Beitrag "Re: avr-gcc: direkter Register Zugriff vs structure-mapping und fehlende Optimierung?"
>
>> In C++ benutze ich schon immer ein structure-mapping mit
>> eingenen Register-Typen, so dass auch nur die richtigen
>> Flags für die Register benutzt werden können, ansonsten
>> Compile-Zeit-Fehler
>
> Könnte man das in C ohne ++ auch haben?

Was hindert Dich denn daran, C++ zu benutzen?

von Ein T. (ein_typ)


Lesenswert?

Ein T. schrieb:
> Was hindert Dich denn daran, C++ zu benutzen?

Lustig, daß es für diese einfache Frage gleich vier negative 
Bewertungen, aber nur eine positive gibt., obwohl die Verwendung von C++ 
sich zunächst nur in der Nutzung eines anderen Compilers mit beinahe 
exakt denselben Optionen und Parametern, sowie in der Nutzung nur dieses 
einen Features erschöpfen, und deswegen also offensichtlich keine 
größeren Änderungen am Projekt und am Code erfordern würde. Die 
Abneigungen und Vorurteile gegen C++ scheinen bei einigen 
Forenteilnehmern ziemlich tief zu sitzen. ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Die Frage war doch, ob etwas auch in C geht, oder nur in C++.

von Bauform B. (bauformb)


Lesenswert?

Ein T. schrieb:
> Was hindert Dich denn daran, C++ zu benutzen?

Dieses. Nur mal ein altes Programm von gcc auf g++ geändert:
1
cc1plus: warning: command line option '-std=c11' is valid for C/ObjC but not for C++
2
cc1plus: warning: command line option '-Wnested-externs' is valid for C/ObjC but not for C++
3
cc1plus: warning: command line option '-Wbad-function-cast' is valid for C/ObjC but not for C++
4
----
5
In file included from imghdr-syslib.c:4:
6
../include/imageheader.h:23:16: error: expected constructor, destructor, or type conversion before '(' token
7
   23 | _Static_assert (sizeof(image_struct) == 108, " Bad struct size");
8
----
9
imghdr-syslib.c:12:4: warning: C++ designated initializers only available with -std=c++2a' or '-std=gnu++2a'
10
   12 |    .top_of_stack           = &tos,   // 00  0 Initial SP (linker script)
11
      |    ^
12
imghdr-syslib.c:13:4: warning: C++ designated initializers only available with -std=c++2a' or '-std=gnu++2a'
13
   13 |    .crt0                   = crt0,   // 04  1 Initial PC "Reset-Handler
Der erste Eindruck: da geht ja einiges nicht mehr... OK, die ersten 
Warnungen sind nur lästig. _Static_assert war ganz nett, aber egal. Aber 
designated initializers würden mir wirklich fehlen.

Edit: es kommt noch "besser":
1
imghdr-syslib.c:17:4: error: either all initializer clauses should be designated or none of them should be

Und noch einen:
1
typedef volatile struct iwdg_struct {
2
// 0x00  IWDG_KR  IWDG Key register
3
   uint32_t  KR;  // 16; //  0  Key value (write only, read 0000h)
4
// 0x04  IWDG_PR  IWDG Prescaler register
5
   uint32_t  PR;  //  3; //  0  PR[2:0] (Prescaler divider)
6
// (...)
7
} iwdg_struct;
8
-----------------
9
../include/STM/iwdg.h:60:3: error: conflicting declaration 'typedef volatile struct iwdg_struct iwdg_struct'
10
   60 | } iwdg_struct;
11
      |   ^~~~~~~~~~~
12
../include/STM/iwdg.h:41:25: note: previous declaration as 'struct iwdg_struct'
13
   41 | typedef volatile struct iwdg_struct {
14
      |                         ^~~~~~~~~~~

nun ja, das ist für mich Grund genug. Ja, das kann man bestimmt alles 
reparieren. Vielleicht beim nächsten Programm.

: Bearbeitet durch User
von MaWin O. (mawin_original)


Lesenswert?

Bauform B. schrieb:
> Dieses

Sagt ja niemand, dass eine Migration ganz ohne Aufwand geht.
C++ ist eben nicht vollständig rückwärtskompatibel zu C.

von Ein T. (ein_typ)


Lesenswert?

Bauform B. schrieb:
> Dieses.

Hm, okay, das sind gute Gründe, wenngleich ich glaube, daß sich die 
meisten davon mit einem aktuellen g++ und "-std=gnu++20" beheben lassen. 
HTH, YMMV.

Ansonsten habe ich leider auch keine Idee, wie sich das mit C lösen 
läßt. Allerdings bin ich keine Referenz, ich benutze C schon lange nur 
noch in sehr, sehr wenigen Ausnahmefällen. ;-)

von Rolf M. (rmagnus)


Lesenswert?

Bauform B. schrieb:
> Der erste Eindruck: da geht ja einiges nicht mehr... OK, die ersten
> Warnungen sind nur lästig.

Da muss man eben die Warnungs-Einstellungen anpassen. Dass der C++-Code 
nicht gleichzeitig C99 sein kann, ist ja logisch.

> _Static_assert war ganz nett, aber egal.

Eigentlich sollte man das eh über das Makro static_assert() verwendet. 
Damit hätte es dann auch in C++ funktioniert.
https://en.cppreference.com/w/c/error/static_assert
https://en.cppreference.com/w/cpp/language/static_assert

> Aber designated initializers würden mir wirklich fehlen.

Die gibt es zwar ab C++20, haben aber den großen Nachteil, dass sie in 
der gleichen Reihenfolge genant sein müssen, in der auch die Members 
definiert sind. Das macht leider den größten Vorteil dieser Art der 
Initialisierung kaputt.

> ../include/STM/iwdg.h:60:3: error: conflicting declaration 'typedef
> volatile struct iwdg_struct iwdg_struct'
>    60 | } iwdg_struct;
>       |   ^~~~~~~~~~~
> ../include/STM/iwdg.h:41:25: note: previous declaration as 'struct
> iwdg_struct'
>    41 | typedef volatile struct iwdg_struct {
>       |                         ^~~~~~~~~~~

Hmm, das scheint nur bei volatile aufzutreten. Ich nehme an, dass sich 
das volatile nicht auf den Typedef überträgt und C++ es deshalb als 
anderen Typ mit gleichem Namen sieht. Generell braucht man in C++ an der 
Stelle aber das typedef gar nicht.

von Markus F. (mfro)


Lesenswert?

Bauform B. schrieb:
> Der erste Eindruck: da geht ja einiges nicht mehr... OK,

Ist es nicht irgendwie - äh - inkonsequent, vom Compiler zu verlangen, 
mehr Fehler zu finden, ohne mehr Fehler zu finden?

von Bauform B. (bauformb)


Lesenswert?

Rolf M. schrieb:
>> Aber designated initializers würden mir wirklich fehlen.
>
> Die gibt es zwar ab C++20, haben aber den großen Nachteil, dass sie in
> der gleichen Reihenfolge genant sein müssen, in der auch die Members
> definiert sind. Das macht leider den größten Vorteil dieser Art der
> Initialisierung kaputt.

Echt jetzt? Ich kann es kaum glauben. Also auch in der allerneuesten 
Version :( Ist das so schwer zu implementieren? Das gibt's doch schon 
seit C11?


Markus F. schrieb:
> Ist es nicht irgendwie - äh - inkonsequent, vom Compiler zu verlangen,
> mehr Fehler zu finden, ohne mehr Fehler zu finden?

Naja, also so gesehen, nun ja... Mein Wunsch ist in Erfuellung gegangen, 
der g++ findet sogar viel mehr Fehler als der gcc, was will ich mehr :)

von Klaus H. (klummel69)


Lesenswert?

Bauform B. schrieb:
> Wilhelm M. schrieb im
>> In C++ benutze ich schon immer ein structure-mapping mit
>> eingenen Register-Typen, so dass auch nur die richtigen
>> Flags für die Register benutzt werden können, ansonsten
>> Compile-Zeit-Fehler
> Könnte man das in C ohne ++ auch haben? Etwas ähnliches erreicht man
> wohl mit Bitfeldern in der struct, aber das ist umständlich, wenn man
> mehrere Bits gleichzeitig setzen muss.

Hi Bauform B,
darf ich nochmal nachfragen: ich verstehe deine Frage nicht.

Dein Code nutzt doch structure mapping?
 Zumnindest zeigst Du später C++ Fehlermeldungen einer HAL in C. Um was 
geht es Dir genau? Willst Du Warnings wenn Du versehentlich falsche 
Konstanten einem Register zuweist?

A la
1
GPIOA.MODE = IWDG_PRESCALER_128;    // UPS
Würde mich auch interessieren, wie Wilhelm M. das gelöst hat.
Hast Du eigene Header in C++ dafür erstellt?

von Bauform B. (bauformb)


Lesenswert?

Klaus H. schrieb:
> Zumnindest zeigst Du später C++ Fehlermeldungen

Das war nur meine Antwort auf die Frage "warum benutzt du nicht C++". 
Ich hatte da nur kurz versucht, ein altes C-Programm mit g++ statt mit 
gcc zu übersetzen.

> Hast Du eigene Header in C++ dafür erstellt?

Nein, überhaupt nicht, ich habe außer diesem Versuch noch nichts mit C++ 
gemacht. Aber alle schwärmen davon und neugierig bin ich auch.

von Klaus H. (klummel69)


Lesenswert?

Bauform B. schrieb:
> Ich hatte da nur kurz versucht, ein altes C-Programm mit g++ statt mit
> gcc zu übersetzen.

Die Frage zielte nicht auf C++.
Der Beispiel-Code, den Du in Deinem Programm nutzt, ist ja C Sourcecode, 
der structure-mapping auf Register nutzt.

Ging es Dir um die Frage wie man jetzt C structure-mappings zusätzlich
mit weiteren Fehleranalysen absichert?

von Klaus H. (klummel69)


Lesenswert?

Wilhelm M. schrieb im
> In C++ benutze ich schon immer ein structure-mapping mit
> eingenen Register-Typen, so dass auch nur die richtigen
> Flags für die Register benutzt werden können, ansonsten
> Compile-Zeit-Fehler

Würde mich auch interessieren, wie Du das gelöst hast.
Hast Du eigene Header in C++ dafür erstellt?

von Wilhelm M. (wimalopaan)


Lesenswert?

Bauform B. schrieb:
> Echt jetzt? Ich kann es kaum glauben. Also auch in der allerneuesten
> Version :( Ist das so schwer zu implementieren? Das gibt's doch schon
> seit C11?

Das ist in C++ so notwendig, denn das ist nun mal die Art, wie die 
Datenelemente eines Objektes initialisiert werden - und das ist seit 
Urzeiten so (s.a. Initialisierungslisten von ctor'en). Von daher ist es 
konsequent, das auch hier so umzusetzen. Tja, einer der Unterschiede 
zwischen C und C++. C++ ist halt keine Obermenge von C.

von Wilhelm M. (wimalopaan)


Lesenswert?

Klaus H. schrieb:
> Wilhelm M. schrieb im
>> In C++ benutze ich schon immer ein structure-mapping mit
>> eingenen Register-Typen, so dass auch nur die richtigen
>> Flags für die Register benutzt werden können, ansonsten
>> Compile-Zeit-Fehler
>
> Würde mich auch interessieren, wie Du das gelöst hast.
> Hast Du eigene Header in C++ dafür erstellt?

Dann solltest Du das auch in dem passenden Thread fragen und nicht hier, 
wo man das nur durch Zufall mitbekommt.

In Kürze:

In dem Aggregat-Typ einer internen Peripherie (z.B. Timer, ...) werden 
statt std::byte spezielle DT verwendet. Diese werden aus templates 
erzeugt, für z.B. DataRegister, ControlRegister, FlagRegister. Je nach 
Semantik der HW-Register.
Parametriert werden diese templates mit den Typen der möglichen Werte 
dieses Registers (bei mir: Aufzählungstypen).
Der aufwändigste Punkt ist also das Erzeugen der enum-Typen. Dies habe 
ich anfänglich zu Fuß gemacht. Hört sich nach viel Arbeit an, ging 
jedoch nach Bedarf (zusammen mit den Aggregaten, dem Adress-Mapping, 
...) und damit überschaubar. Dann hatte ich mal ein ein Python-Script, 
was auch der XML-Beschreibung der Peripherie-Register das Zeug erzeugt 
hat. Das funktioniert aber leider nicht mehr, weil das XML-Schema sich 
geändert hat. Nun mache ich notwendige Ergänzungen wieder nach Bedarf 
;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Bauform B. schrieb:
> Rolf M. schrieb:
>>> Aber designated initializers würden mir wirklich fehlen.
>>
>> Die gibt es zwar ab C++20, haben aber den großen Nachteil, dass sie in
>> der gleichen Reihenfolge genant sein müssen, in der auch die Members
>> definiert sind. Das macht leider den größten Vorteil dieser Art der
>> Initialisierung kaputt.
>
> Echt jetzt? Ich kann es kaum glauben.

Problem bei C++ ist, dass ein Initializer das Ergebnis eines 
Funktionsaufrufs sein darf, und so ein Funktionsaufruf kann 
Seiteneffekte haben.  Intuitiv wüede man die Funktionsaufrufe "von links 
nach rechts" auswerten, und das Ergebnis wäre denn i.A. abhängig von der 
Reihenfolge.

Eine Design-Entscheidung wäre, die Verantwortung komplett dem Anwender 
zu überlassen.

Eine andere Design-Entscheidung wäre, etwas Ordnung in die Sache zu 
bringen und nur Initializer in ihrer natürlchen Reihenfpolge zuzulassen.

Offenbar hat man den "sichereren" Weg No. 2 gewählt.

...und solche Problemchen hat man in C nicht, weil da ein Initializer 
nicht das Ergebnis eines Funktionsaufrufs sein darf, auch wenn das 
Ergebnis zu Compilezeit bekannt ist.  Keine Ahnung wie das mit C23 + 
constexpr gelöst ist; vermutlich dadurch, dass constexpr-Funktionen 
keine Seiteneffekte haben dürfen, so dass deren Aufrufe kommutieren.

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Johann L. schrieb:
> Problem bei C++ ist, dass ein Initializer das Ergebnis eines
> Funktionsaufrufs sein darf, und so ein Funktionsaufruf kann
> Seiteneffekte haben.
>
> Eine andere Design-Entscheidung wäre, etwas Ordnung in die Sache zu
> bringen und nur Initializer in ihrer natürlchen Reihenfpolge zuzulassen.

OK, wenigstens gibt es eine vernünftige Erklärung, danke dafür! Man kann 
eben nicht alles auf einmal haben...

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Bauform B. schrieb:
>> Echt jetzt? Ich kann es kaum glauben. Also auch in der allerneuesten
>> Version :( Ist das so schwer zu implementieren? Das gibt's doch schon
>> seit C11?
>
> Das ist in C++ so notwendig, denn das ist nun mal die Art, wie die
> Datenelemente eines Objektes initialisiert werden - und das ist seit
> Urzeiten so (s.a. Initialisierungslisten von ctor'en). Von daher ist es
> konsequent, das auch hier so umzusetzen.

Das stimmt aber nicht. Ich wünschte, es wäre so wie bei den 
Initialisierungslisten von Konstruktoren. Bei denen kann man die Member 
auch in einer anderen Reihenfolge angeben. Die Initialisierung erfolgt 
dann in der Reihenfolge der Definition der Member, nicht in der 
Reihenfolge in der Initialisierungsliste.
Bei den designated initializers bricht der Compiler dagegen mit Fehler 
ab, wenn die Reihenfolge nicht übereinstimmt. Also ein grundlegend 
unterschiedliches Verhalten.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Bauform B. schrieb:
>>> Echt jetzt? Ich kann es kaum glauben. Also auch in der allerneuesten
>>> Version :( Ist das so schwer zu implementieren? Das gibt's doch schon
>>> seit C11?
>>
>> Das ist in C++ so notwendig, denn das ist nun mal die Art, wie die
>> Datenelemente eines Objektes initialisiert werden - und das ist seit
>> Urzeiten so (s.a. Initialisierungslisten von ctor'en). Von daher ist es
>> konsequent, das auch hier so umzusetzen.
>
> Das stimmt aber nicht.

Was stimmt nicht?

> Ich wünschte, es wäre so wie bei den
> Initialisierungslisten von Konstruktoren. Bei denen kann man die Member
> auch in einer anderen Reihenfolge angeben. Die Initialisierung erfolgt
> dann in der Reihenfolge der Definition der Member, nicht in der
> Reihenfolge in der Initialisierungsliste.

Genau. Das sagte ich oben.

> Bei den designated initializers bricht der Compiler dagegen mit Fehler
> ab, wenn die Reihenfolge nicht übereinstimmt. Also ein grundlegend
> unterschiedliches Verhalten.

Nein.
Die Datenelemente werden immer in derselben Reihenfolge initialisiert. 
In dem einen wie in dem anderen Fall.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Was stimmt nicht?

Dass das Verhalten gleich wäre.

>> Bei den designated initializers bricht der Compiler dagegen mit Fehler
>> ab, wenn die Reihenfolge nicht übereinstimmt. Also ein grundlegend
>> unterschiedliches Verhalten.
>
> Nein.
> Die Datenelemente werden immer in derselben Reihenfolge initialisiert.
> In dem einen wie in dem anderen Fall.

Der Standard sagt unter "List-initialization":

"The ordered identifiers in the designators of the 
designated-initializer-list shall form a subsequence of the ordered 
identifiers in the direct non-static data members of T."

und bringt auch ein Beispiel:
1
struct A { int x; int y; int z; };
2
A a{.y = 2, .x = 1}; // error: designator order does not match declaration order
3
A b{.x = 1, .z = 2}; // OK, b.y initialized to 0

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Was stimmt nicht?
>
> Dass das Verhalten gleich wäre.

Ich habe davon gesprochen, dass die Reihenfolge in beiden Fällen gleich 
ist. Ich habe nicht davon gesprochen, dass u.U. eine Warnung auftritt 
wogegen im anderen Fall ein Fehler.

Also: die Reihenfolge der Initialisierung ist (und muss) immer gleich 
sein.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Rolf M. schrieb:
>> Wilhelm M. schrieb:
>>> Was stimmt nicht?
>>
>> Dass das Verhalten gleich wäre.
>
> Ich habe davon gesprochen, dass die Reihenfolge in beiden Fällen gleich
> ist.

Nö. Das hast du vielleicht gemeint, aber gesprochen hast du davon 
nirgends.
Es ging um diese Aussage:

Rolf M. schrieb:
>> Aber designated initializers würden mir wirklich fehlen.
>
> Die gibt es zwar ab C++20, haben aber den großen Nachteil, dass sie in
> der gleichen Reihenfolge genant sein müssen, in der auch die Members
> definiert sind.

und du meintest dazu:

Wilhelm M. schrieb:
> Das ist in C++ so notwendig, denn das ist nun mal die Art, wie die
> Datenelemente eines Objektes initialisiert werden - und das ist seit
> Urzeiten so (s.a. Initialisierungslisten von ctor'en). Von daher ist es
> konsequent, das auch hier so umzusetzen.

Aber genau diese Vorgabe (Reihenfolge bei den Initializers muss der bei 
der Definition entsprechen) ist bei den 
Konstruktor-Initialisierungslisten so nicht gegeben. Also ist es eben 
nicht konsequent, weil unterschiedlich umgesetzt.
Und genau dieser Zwang zur gleichen Reihenfolge ist das, was mich an den 
designated-initializers in C++ wirklich stört.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Das ist in C++ so notwendig, denn das ist nun mal die Art, wie die
>> Datenelemente eines Objektes initialisiert werden - und das ist seit
>> Urzeiten so (s.a. Initialisierungslisten von ctor'en). Von daher ist es
>> konsequent, das auch hier so umzusetzen.
>
> Aber genau diese Vorgabe (Reihenfolge bei den Initializers muss der bei
> der Definition entsprechen) ist bei den
> Konstruktor-Initialisierungslisten so nicht gegeben.

Wenn Du genau liest, steht dort, wie die Objekte initialisiert werden! 
Und die ist nun mal immer gleich (egal wie die Initialisierungsliste 
geordnet ist). Den Verweis auf die Initlisten habe ich dort deswegen 
gezogen, weil auch dort die Reihenfolge eben auch der 
Deklarationsreihenfolge entspricht, egal wie die Initliste geordnet ist. 
Dort gibt es leider(!) nur eine Warnung.

von Sheeva P. (sheevaplug)


Lesenswert?

Wilhelm M. schrieb:
> Der aufwändigste Punkt ist also das Erzeugen der enum-Typen. Dies habe
> ich anfänglich zu Fuß gemacht. Hört sich nach viel Arbeit an, ging
> jedoch nach Bedarf (zusammen mit den Aggregaten, dem Adress-Mapping,
> ...) und damit überschaubar. Dann hatte ich mal ein ein Python-Script,
> was auch der XML-Beschreibung der Peripherie-Register das Zeug erzeugt
> hat. Das funktioniert aber leider nicht mehr, weil das XML-Schema sich
> geändert hat. Nun mache ich notwendige Ergänzungen wieder nach Bedarf
> ;-)

Läßt sich das Python-Skript nicht an das neue XML-Schema anpassen?

von Klaus H. (klummel69)


Lesenswert?

Wilhelm M. schrieb:
> Klaus H. schrieb:
>> Würde mich auch interessieren, wie Du das gelöst hast.
>> Hast Du eigene Header in C++ dafür erstellt?
> Dann solltest Du das auch in dem passenden Thread fragen und nicht hier,
> wo man das nur durch Zufall mitbekommt.

Sorry, du hattest in diesem Thread schon teilgenommen und im anderen 
Thread ging es ja eher um ein Compiler Problem.

Kannst Du mal ein Beispiel zeigen? Ich hatte schon verschieden Varianten 
mit templates und structs überlegt. Aber keine davon war so, dass ich 
das Gefühl hatte: ja, die erhöhte Fehleraufdeckung rechtfertigt den 
Aufwand.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Bauform B. schrieb:
> Aber
> designated initializers würden mir wirklich fehlen.

Ich wüßte nicht, wie ich ohne die klarkommen sollte.
Sich nur auf die Reihenfolge verlassen zu müssen, erscheint mir extrem 
fehlerträchtig.
Ich habe oft Arrays von Structs, die sehr groß werden, da kann ich mir 
nicht alles merken. Und bei Änderungen würde ja alles durcheinander 
gewürfelt.
Hier mal ein Auszug:
1
  .par.dac[DAC_VENERGY].gain = DAC_6KV_GAIN,
2
  .par.dac[DAC_VENERGY].offset = DAC_6KV_OFFSET,
3
  .par.dac[DAC_VENERGY].lower = 0.0,
4
  .par.dac[DAC_VENERGY].upper = MOD_6KV_LIMIT,
5
  .par.dac[DAC_VENERGY].val = 0.0 * MOD_6KV_SGAIN,
6
  .par.adc[ADC_VENERGY].gain = MON_6KV_GAIN,
7
  .par.adc[ADC_VENERGY].offset = MON_6KV_OFFSET,
8
  .par.adc[ADC_IENERGY].gain = MONI_6KV_GAIN,
9
  .par.adc[ADC_IENERGY].offset = MONI_6KV_OFFSET,
10
  .par.adc[ADC_IENERGY].comp = MONI_6KV_COMP,

Man sieht hier, daß die Parameter je Modul gruppiert sind, die sich aber 
in Structs an 3 verschiedenen Adressen befinden.
Ein Zwang zu aufsteigenden Adressen würde alles vollkommen unleserlich 
machen.

: Bearbeitet durch User
von Klaus H. (klummel69)


Lesenswert?

OK, das geht in C++ so nicht, aber ich finde die Darstellung nicht gut. 
Darin sehe ich keinen Vorteil. Es geht die Hierarchie der Daten 
verloren.
Eine verschaltelte Initialisierung finde ich besser. So müsste es in C 
und in C++20 funktionieren.
1
data_t data = { 
2
  .par = {  
3
    .dac = {  
4
        { /*DAC_VENERGY*/
5
        .gain = DAC_6KV_GAIN, 
6
        .offset = DAC_6KV_OFFSET, 
7
        .lower = 0.0,
8
        .upper = MOD_6KV_LIMIT,
9
        .val = 0.0 * MOD_6KV_SGAIN 
10
        }
11
    },
12
    .adc = {
13
        { /* ADC_VENERGY */
14
        .gain = MON_6KV_GAIN,
15
        .offset = MON_6KV_OFFSET
16
        },
17
        { /* ADC_IENERGY*/ 
18
        .gain = MONI_6KV_GAIN,
19
        .offset = MONI_6KV_OFFSET,
20
        .comp = MONI_6KV_COMP
21
        }
22
    }
23
  }
24
};



Ein Nachteil in C++ ist IMHO das Array designators nicht funktionieren. 
Aber das ist für micht verschmerzbar.

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:
> Ich habe oft Arrays von Structs, die sehr groß werden, da kann ich mir
> nicht alles merken. Und bei Änderungen würde ja alles durcheinander
> gewürfelt.

Was sollte da durcheinander gewürfelt werden?

von Peter D. (peda)


Lesenswert?

Wilhelm M. schrieb:
> Was sollte da durcheinander gewürfelt werden?

Ich meinte, wenn man keine designated initializers verwenden könnte. Ich 
hab das hier im Forum kennen und schätzen gelernt und benutze es seitdem 
ausschließlich.
Die Initialisierung nach Reihenfolge hatte mich schon immer geärgert und 
oft Fehler verursacht. Während einer Projektentwicklung kommt es 
regelmäßig vor, daß Elemente verschoben, hinzugefügt, umbenannt oder 
gelöscht werden.
Ich kenne keinen, wo schon zu Anfang gleich alles in Stein gemeißelt 
ist.
Dagegen spricht schon, daß die Anwender nach der ersten Version noch 
haufenweise Extrawünsche haben, die man nachträglich implementieren muß.
Ich arbeite daher auch gerne mit enums, die die Order in einem Array 
festlegen. Ich überlasse also nichts dem Zufall.
Perfekt wäre es noch, wenn man auch bei einem Funktionsaufruf die 
Argumente namentlich übergeben könnte, d.h. nicht zwingend nach 
Reihenfolge. Da oft 3-4 Argumente ausreichen, kann ich mir das grad noch 
merken.

: Bearbeitet durch User
Beitrag #7374072 wurde vom Autor gelöscht.
Beitrag #7410205 wurde von einem Moderator gelöscht.
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.