Problem mit AVR-GCC:
Ich hab ein Array in einem Objekt.
Nun müssen aber auch andere Objekte wissen, wie groß das Array ist.
Gibt es dafür ne andere Lösung, außer daß ich die Einträge immer
abzählen muß und dann ins h-File reinschreiben?
Die Tabelle selber darf ich ja nicht ins h-File schreiben, das gibt nen
bösen Error: multiple definition of `TAB_PWM'
soweit ich weiss gibt es das nicht, du aber üblich ist am ende z.b. ein
0 reinzuschrieben und alle funktionen gehen das array bis zur 0 durch
und wissen das dann schluss ist.
Das geht leider nicht so einfach.
Eine "saubere" Methode wäre einen typedef in eine .h Datei zu schreiben:
typedef prog_uint8_t PWMTab_t[<benötigte größe>];
Die Größe kann dann mit sizeof(PWMTab_t) abgefragt werden. Aber ja: Du
musst hier auch die Größe immer von Hand neu eintragen.
Wenn man die Größe wirklich zur Compilezeit braucht, etwa weil andere
Objekte davon abhängen, gibt's nicht wirklich eine überzeugende Lösung.
Ich hab ein ähnlichen Problem bei der Bestimmung einer Puffergröße
(union), in der Objekte mehrere unabhängiger Module enthalten sein
können.
Lösung 1
Wenn das Objekt nur 1x referenziert wird, dann geht ein
1
// #Einträge: sizeof (array) / sizeof (array[0])
2
staticconsttype_tarray[]={...};
im Header.
Wenn das Objekt in einem Modul nicht referenziert wird (sizeof
referenziert nicht), dann legt gcc auch kein Objekt dafür an. Ansonsten
erhält man wohl mehrere lokale Kopien von dem Ding.
Falls es mehrfach referenziert wird und im LST auftaucht, versuch es mal
als .weak zu definieren.
Lösung 2
Man schreibt die Größe in eine Variable, allerdings ist sie dann
ausserhalb des definierenden Moduls nicht zur Compilezeit bekannt,
sondern erst zur Laufzeit:
Simon K. wrote:
> Die Größe kann dann mit sizeof(PWMTab_t) abgefragt werden. Aber ja: Du> musst hier auch die Größe immer von Hand neu eintragen.
Eigentlich wäre das nicht weiter schlimm, das Ärgernis daran ist, daß,
wenn sich mal die Arraygröße ändert, man keinen Fehler/Warnung bekommt
bzw. erzeugen kann.
Es gibt keine Möglichkeit, zur Compilezeit die Korrektheit der Größe
zu testen, auch wenn alles Compilezeit-Konstanten sind. Sowas wie
__builtin_error oder __builtin_warning vermisse ich schon lange in GCC,
welche man zB zusammen mit __builtin_constant_p oder
__builtin_choose_expr verwenden könnte, um bei Differenzen zu meckern.
IMHO liegt das eiegentliche Problem darin, wie in C der Konflikt
zwischen Deklaration und Definition aufgelöst wird, wenn gleichzeitig
extern und eine Initialisierung angegeben ist.
Seit je her ist es so, dass dann die Initialisierung gewinnt und das
Ganze eine Definition ist. Compiler bzw. Linker, die eine multiple
Definition ignorieren, kommen damit gut zurecht, aber standardkonform
ist das natürlich nicht.
Hab ich mich auch schon oft drüber geärgert, denn im Grunde macht sowas
eine vernünftige Verwendung von Konstanten ebenfalls unmöglich.
constants.h
1
externconstintNrSteps=5;
2
externconstdoublePi=3.141592654;
includiert in 2 Translation Units -> multiple definition error
Nimmst du aber die Initialisierung raus, dann nimmst du dem Compiler
eine Mange von Optimiermöglichkeiten weg, die eigentlich trivial sind.
Also bleibt wieder nichts anderes übrig als über Präprozessorkonstanten
zu gehen. Und davon will man ja eigentlich seit Jahren wegkommen.
Gerade hier sollte doch static const gut gangbar sein?
Selbst wenn das extern nicht zu einem Fehler führt wenn der Compiler die
Instanziierung nur 1x sieht, kann er nicht optimieren, weil sich ein
const-Objekt ändern kann. const bedeutet nur so viel wie "read only",
aber nicht, daß das Ding nach der Initialisierung immer diesen Wert hat!
Bei static kann der Compiler jedoch sehen, ob Zugriffe da sind, etw
Schweiereien (die man nicht verwenden will, aber die ein Compiler
handhaben können muss, weil sie prinzipiell auftreten können) wie
Johann L. wrote:
> Gerade hier sollte doch static const gut gangbar sein?
Ja, das hab ich beim schreiben übersehen. static ist ne Möglichkeit.
>> Selbst wenn das extern nicht zu einem Fehler führt wenn der Compiler die> Instanziierung nur 1x sieht, kann er nicht optimieren, weil sich ein> const-Objekt ändern kann.
Huch, wie das?
> const bedeutet nur so viel wie "read only",> aber nicht, daß das Ding nach der Initialisierung immer diesen Wert hat!
Doch, genau das bedeutet const.
Eine const Variable bedeutet immer, dass sich der Wert nach der
Initialisierung nicht mehr verändert. Wenn der Compiler also den Wert
kennt, kann er ihn für Optimierungen benutzen. Wenn du etwas als const
deklarierst und das Ding ändert sich nach der Initialisierung, hast du
den Compiler angelogen und darfst ihn nicht für Fehler verantwortlich
machen.
> Bei static kann der Compiler jedoch sehen, ob Zugriffe da sind, etw> Schweiereien (die man nicht verwenden will, aber die ein Compiler> handhaben können muss, weil sie prinzipiell auftreten können) wie>>
1
>*((int*)&NrSteps)=6;
2
>
Äh, nein. Das muss ein Compiler nicht handhaben. Wenn du nach dieser
'Modifikation' den Wert von NrSteps ausgibst, und am stdout erscheint
eine 5, dann ist das völlig in Ordnung.
Karl heinz Buchegger wrote:
> Johann L. wrote:>>> Gerade hier sollte doch static const gut gangbar sein?>> Ja, das hab ich beim schreiben übersehen. static ist ne Möglichkeit.>>>>> Selbst wenn das extern nicht zu einem Fehler führt wenn der Compiler die>> Instanziierung nur 1x sieht, kann er nicht optimieren, weil sich ein>> const-Objekt ändern kann.>> Huch, wie das?
Historische Altlast.
http://en.wikipedia.org/wiki/Const_correctness#Loopholes_to_const-correctness
Aber keine Ahnung, wie der momentane GCC das handhabt...
Karl heinz Buchegger wrote:
>> Selbst wenn das extern nicht zu einem Fehler führt wenn der Compiler die>> Instanziierung nur 1x sieht, kann er nicht optimieren, weil sich ein>> const-Objekt ändern kann.>> Huch, wie das?>>> const bedeutet nur so viel wie "read only",>> aber nicht, daß das Ding nach der Initialisierung immer diesen Wert hat!
Ich hab sowas schonmal gemacht und es geht sehr gut.
Ein Task liest über 74HC165 digitale Eingänge ein und legt sie im SRAM
ab.
Für alle anderen Tasks sind diese Eingänge im SRAM als const definiert,
d.h. sie dürfen sie lesen, aber nicht ändern.
Ansonsten würden sie ja kein Abbild der physischen Eingänge am 74HC165
mehr sein.
Peter
Johann L. wrote:
>> Huch, wie das?>> Historische Altlast.>> http://en.wikipedia.org/wiki/Const_correctness#Loopholes_to_const-correctness>> Aber keine Ahnung, wie der momentane GCC das handhabt...
Was sagt dir der Satz
"It should be noted, however, that any attempt to modify an object that
is itself declared const by means of const_cast results in undefined
behavior"
Karl heinz Buchegger wrote:
> Was sagt dir der Satz> "It should be noted, however, that any attempt to modify an object that> is itself declared const by means of const_cast results in undefined> behavior"
Es gibt Fallstricke, wie ich schrieb. Insbesondere auch dann, wenn ein
Komposit const ist, seine Komponenten hingegen nicht.
Peter Dannegger wrote:
> Karl heinz Buchegger wrote:>>> Selbst wenn das extern nicht zu einem Fehler führt wenn der Compiler die>>> Instanziierung nur 1x sieht, kann er nicht optimieren, weil sich ein>>> const-Objekt ändern kann.>>>> Huch, wie das?>>>>> const bedeutet nur so viel wie "read only",>>> aber nicht, daß das Ding nach der Initialisierung immer diesen Wert hat!>> Ich hab sowas schonmal gemacht und es geht sehr gut.> Ein Task liest über 74HC165 digitale Eingänge ein und legt sie im SRAM> ab.
Klar. Da der Optimizer keinen Zahlenwert hat um den Zugriff zu ersetzen,
bleibt ihm letztendlich nichts anderes übrig als den Zugriff tatsächlich
zu machen. Effektiv hast du damit ein 'read only' erreicht.
Aber: Nichts und niemand aus dem Sprachstandard hindert den Optimizer
letztendlich das ganze so zu gestalten, dass er den Zugriff nur beim
ersten mal macht, um in weiterer Folge den bereits gelesenen Wert bei
allen anderen Abfragen zu verwenden.
Klar. Kein Compilerbauer wird das je so machen. Aber es ist auch nicht
explizit verboten.
Es gibt durchaus Leute in comp.lang.c die über folgendes gestolpert sind
1
intmain()
2
{
3
constinti=5;
4
5
*(int*)&i=6;
6
7
printf("%d\n",i);
8
}
und die Ausgabe war: 5
und 5 ist ein völlig 'korrektes' Ergebnis, denn nach dem wegcasten des
const (egal wie das passiert) entsteht automatisch undefiniertes
Verhalten.
Karl heinz Buchegger wrote:
> Es gibt durchaus Leute in comp.lang.c die über folgendes gestolpert sind>>
1
>intmain()
2
>{
3
>constinti=5;
4
>
5
>*(int*)&i=6;
6
>
7
>printf("%d\n",i);
8
>}
9
>
>> und die Ausgabe war: 5
Hier ist die Gemängelage anders, weil i nicht extern ist sondern auto.
Und es ging auch nicht darum Hack zu befordern, sondern daß man sich
nicht wundern muss, falls der Compiler was nicht wegoptmiert obwohl man
das ganz nett fände.
Johann L. wrote:
> Hier ist die Gemängelage anders, weil i nicht extern ist sondern auto.
Ist aber trotzdem nur syntaktischer Zucker
a.c
1
#include<stdio.h>
2
3
externconstintconst_i;
4
5
intmain()
6
{
7
*(int*)&const_i=6;
8
9
printf("%d\n",const_i);
10
}
b.c
1
externconstintconst_i=4;
liefert zb. auf VC++ eine Access Violation. Und das darf der Compiler
auch
so umsetzen.
Im Übrigen hab ich mich hier
> Hab ich mich auch schon oft drüber geärgert, denn im Grunde macht> sowas eine vernünftige Verwendung von Konstanten ebenfalls unmöglich.>>constants.h> extern const int NrSteps = 5;> extern const double Pi = 3.141592654;>> includiert in 2 Translation Units -> multiple definition error
geirrt. Lass einfach das extern weg und gut ists.
const zusammen mit einer Initialisierung ist dasselbe wie static.
Das man damit allerdings Arrays duplizieren wird, steht auf einem
anderen Blatt und ist ja das was Peter von Anfang an bekrittelt hat.
Karl heinz Buchegger wrote:
>> Hab ich mich auch schon oft drüber geärgert, denn im Grunde macht>> sowas eine vernünftige Verwendung von Konstanten ebenfalls unmöglich.>>>>constants.h>> extern const int NrSteps = 5;>> extern const double Pi = 3.141592654;>>>> includiert in 2 Translation Units -> multiple definition error>> geirrt. Lass einfach das extern weg und gut ists.
Hmmm. Bei mir meckert gcc 4.4 das an, egal ob mit -fcommon oder
-fno-common. Das einzige was hilft ist ein __attribute__((weak)), oder
mit welchem Compiler hast du das übersetzt? Bzw mit welchem Linker die
Objekte gelinkt?
> Das man damit allerdings Arrays duplizieren wird, steht auf einem> anderen Blatt und ist ja das was Peter von Anfang an bekrittelt hat.
Hallo,
also teilweise sträuben sich mir hier beim Lesen die Haare.
Die Frage, wie eine Sache zu lösen ist entscheidet die Sprachdefinition.
Das Handling von Const wird z.B. durch die formale Definition bestimmt.
Ob die reale Implementierung das dann so handhabt ist eine andere Frage.
Innerhalb von C ist definiert, dass CONST eine Variable nicht mehr
änderbar macht. Wenn ein bestimmter COmpiler dies also zulässt, so nenne
ich das eine Bug.
Etwas anderes ist das programmieren um eine Bug herum, hier sollte man
versuchen, mit den funktionierenden Mitteln des Standards den Bug zu
vermeiden oder zu korrigieren.
Konsequenz: eine Programmierung auf der Basis von Bugs ist für mich
nicht tragbar, ist nicht professionell, weil mir jede neue
Compilerversion potentiell die Basis unterm Hintern wegzieht.
Wer hier also schreibt, daß const == static ist, der sollte seine
Meinung nochmal überdenken.
Gruß,
Michael
Peter Dannegger wrote:
> Problem mit AVR-GCC:>> Die Tabelle selber darf ich ja nicht ins h-File schreiben, das gibt nen> bösen Error: multiple definition of `TAB_PWM'> [c]>> prog_uint8_t TAB_PWM[] = { // logarithmic table> 1,> 1,> 2,>schnipp-schnapp> 202,> 255> };>> Peter
Hallo,
ich habe derartige Dinge bsiher so gelöst, daß ich mit 0 terminiere und
zur Laufzeit abzähle. Also
typedef menu_item_t {uint8_t x, y; uint16_t * handler, uint16_t * data}
menu_item_t;
menu_item_t item1 PROGMEM = {0, 0, dispmenu, &submenu};
menu_item_t item2 PROGMEM = {0, 0, dispmenu, &submenu};
menu_item_t item3 PROGMEM = {0, 0, dispmenu, &submenu};
menu_item_t item4 PROGMEM = {0, 0, dispmenu, &submenu};
menu_item_t * menu1[] PROGMEM = {&item1, &item2, &item3, &item4, 0}
...ein paar casts (uint16_t) habe ich weggelassen.
Entweder ich zähle einmal vorab in eine lokale Variable, oder die 0 wird
als Terminator in der Schleife abgefragt.
Gruß,
Michael
Michael Appelt wrote:
> Wer hier also schreibt, daß const == static ist, der sollte seine> Meinung nochmal überdenken.
Mein Fehler.
Das ist nur in C++ so, dass const Variablen automatisch internal linkage
(also static) sind. In C blieb alles beim alten.
Bin wohl schon zu lange von C weg.
Hallo Peter,
Ich will ja nix sagen :-X
ich hatte zwar kurz zur Sicherheit gegurgelt, aber in welches Cxy ich
geraten war habe ich garnicht geprüft. GLück gehabt.
BTW sehe ich eine Lösung für das zweite Problem: const für eine lokale
Tabelle im Modul und dann nur einen öffentlichen Pointer darauf.
Gruß,
Michael