Hi, wie ich beim debuggen feststellen musste packt der Linker Variablen, die in getrennten Modulen liegen (nur Modul intern) zu einer Variablen zusammen wenn sie den gleichen Namen haben. Auszug der Deklarationen: in Main.c volatile uint16_t impwidth_limit; in impuls.c volatile uint16_t impwidth_limit _attribute_ ((section (".noinit"))); wenn man bei einer der beiden Variablen den Namen ändert sieht man bei der Angabe des belegten RAM's sofort, das unterschiedliche Namen zu 2byte Mehrbelegung führen. Ich habe jetzt nicht ausprobiert, ob das nur in Verbindung mit ".noinit" passiert. Gruß Ingo
Es ist die gleiche Variable in diesem Falle. Schau dir das C-Schlüselwort static an.
Hi, das verstehe ich nicht, denn das würde ja heißen, das man alle Variablen in Modulen als static deklarieren müsste, selbst wenn sie nicht exportiert werden um bei zufälligen gleichen Variablen Namen in anderen Modulen diesen Effekt zu verhindern. Sollte das in "C" oder gcc wirklich so gewollt sein, da doch die export Funktion ausreichend sein sollte. Gruß Ingo
Wovon redest du? Es gibt in C kein explizites "export". Wenn du kein static davor setzt, ist es eine globale (modulübergreifend) Variable, wird also quasi automatisch exportiert.
Ingo Stahl schrieb: > Hi, > > das verstehe ich nicht, denn das würde ja heißen, das man alle Variablen > in Modulen als static deklarieren müsste, selbst wenn sie nicht > exportiert werden um bei zufälligen gleichen Variablen Namen in anderen > Modulen diesen Effekt zu verhindern. Ja, so ist es. > Sollte das in "C" oder gcc wirklich so gewollt sein, da doch die export > Funktion ausreichend sein sollte. Das hat nichts mit GCC zu tun. Das ist in der Sprache 'C' so definiert. Eine Funktion oder Schlüsselwort 'export' gibt es in 'C' erstmal nicht. Da haben manche Leute ein '#define export extern' gebaut. So wird 'export' häufig verwendet. Ich persönlich finde es sehr unglücklich da es verwirrt, wie sich hier gerade zeigt.
900ss D. schrieb: > Da haben manche Leute ein '#define export extern' gebaut. So wird > 'export' häufig verwendet. > Ich persönlich finde es sehr unglücklich da es verwirrt, wie sich hier > gerade zeigt. Außerdem ist das doch auch von der Bedeutung her völlig verquer. Ein '#define import extern' wäre da ja schon sinnvoller.
Genaugenommen kommt hier noch eine lästige GCC-Gewohnheit zum Tragen: Werden in zwei Modulen nichtstatische Variablen gleichen Namens angelegt, so gibt der Linker keine Fehlermeldung aus, sondern fasst alle doppelt definierten Symbole zusammen. Andere Linker machen das nicht und geben entsprechende Fehlermeldungen aus. Dem GCC lässt sich dieses Verhalten mit -fno-common auch abgewöhnen.
Hi, danke für die Antworten. Es ist also ein Feature, das ich mir Merken muss um nicht noch einmal darauf reinzufallen. Mit export meinte ich übrigens das "extern" Schlüsselwort, da ich das mit exportieren einer Variablen nach außen verinnerlicht habe. Daher habe ich das "static" als "Ausfuhrstop" wohl nicht mehr im Sinn gehabt. Gruß Ingo
Rufus Τ. Firefly schrieb: > so gibt der Linker keine Fehlermeldung aus Wie? Da bin ich bisher nicht drüber gestolpert. Das ist schon ziemlich dumm. Da sucht man sich ja tot, wenn einem das passiert.
Ingo Stahl schrieb: > mit exportieren einer Variablen nach außen verinnerlicht habe. Daher > habe ich das "static" als "Ausfuhrstop" wohl nicht mehr im Sinn gehabt. Du sollst sogar static verwenden, wo du nur kannst. Denn surch static baust du eine Barriere rund um deine Compilation Unit auf. Du sagst dem Compiler explizit: Diese Variable oder diese Funktion KANN nicht von ausserhalb referenziert werden. Sie ist ausserhalb nicht sichtbar. Das wiederrum ermöglicht dem Compiler so manche Optimierung, bis hin zu: Funktionen können geinlined werden, ohne dass ein klassische aufrufbare Implementierung der Funktion existieren muss.
Ist mir auch schon aufgefallen, daß der GCC stillschweigend Mehrfachdefinitionen als eine Variable zusammenfast. Der Keil C51, zeigt mir bei sowas sofort die rote Karte. Wenn -fno-common diesen Fehler behebt, sollte man das als default in jedes Make mit aufnehmen. Peter
Zum Nachlesen hier die Info aus der GCC Doku: -fno-common In C code, controls the placement of uninitialized global variables. Unix C compilers have traditionally permitted multiple definitions of such variables in different compilation units by placing the variables in a common block. This is the behavior specified by -fcommon, and is the default for GCC on most targets. On the other hand, this behavior is not required by ISO C, and on some targets may carry a speed or code size penalty on variable references. The -fno-common option specifies that the compiler should place uninitialized global variables in the data section of the object file, rather than generating them as common blocks. This has the effect that if the same variable is declared (without extern) in two different compilations, you will get a multiple-definition error when you link them. In this case, you must compile with -fcommon instead. Compiling with -fno-common is useful on targets for which it provides better performance, or if you wish to verify that the program will work on other systems which always treat uninitialized variable declarations this way.
Peter Dannegger schrieb: > Ist mir auch schon aufgefallen, daß der GCC stillschweigend > Mehrfachdefinitionen als eine Variable zusammenfast. Historisches Unix-Compiler-Verhalten, ist durch den Standard explizit gedeckt (als eine Möglichkeit). Meine Vermutung ist, dass das "Ur-C" das Schlüsselwort "extern" noch nicht kannte. Durch die Implementierung globaler Variablen als ein common block (FORTRAN lässt grüßen ;-) konnte man dann den gleichen Effekt erreichen. Das "static" nicht das default-Verhalten einer Deklaration/Definition ist, ist eigentlich ein Designfehler von C. Kann man aber nicht mehr beheben, ohne dass die gesamte C-Welt zusammenbrechen würde. Man kann sich nur angewöhnen, prinzipiell überall "static" davor zu schreiben.
Jörg Wunsch schrieb: > Historisches Unix-Compiler-Verhalten, ist durch den Standard explizit > gedeckt (als eine Möglichkeit). Mag ja sein. Aber es spricht nichts dagegen, die Möglichkeit nur auf Wunsch und nicht per Default zu aktivieren, denn sie verschleiert Programmierfehler, wie die Definition von globalen Variablen in Headerdateien. Zumal diejenigen, die gccavr verwenden, das ziemlich sicher nicht tun, um irgendwelche alten K&R-C-Fragmente aus alten Unix-Zeiten zu übersetzen.
Rufus Τ. Firefly schrieb: > Mag ja sein. Aber es spricht nichts dagegen, die Möglichkeit nur auf > Wunsch und nicht per Default zu aktivieren, denn sie verschleiert > Programmierfehler, wie die Definition von globalen Variablen in > Headerdateien. Vermutlich muss man nur eine Konfigurationsanweisung umschalten irgendwo in den Untiefen der AVR-Anpassung. Zumindest suggeriert die Doku ja, dass es Plattformen gibt, auf denen -fno-common die Voreinstellung ist. Da auf dem AVR dem -fcommon als Default sicher keiner hinterher weinen wird, bliebe es also nur, diese Stelle zu finden und einen Bugreport mitsamt Patch zu schreiben und den dann auch durchzuboxen.
Jörg Wunsch schrieb: > Vermutlich muss man nur eine Konfigurationsanweisung umschalten > irgendwo in den Untiefen der AVR-Anpassung. Zumindest suggeriert > die Doku ja, dass es Plattformen gibt, auf denen -fno-common die > Voreinstellung ist. > > Da auf dem AVR dem -fcommon als Default sicher keiner hinterher weinen > wird, bliebe es also nur, diese Stelle zu finden und einen Bugreport > mitsamt Patch zu schreiben und den dann auch durchzuboxen. In ./gcc/config/avr/avr.c
1 | /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
|
2 | static const struct default_options avr_option_optimization_table[] = |
3 | {
|
4 | { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, |
5 | + { OPT_LEVELS_ALL, OPT_fcommon, NULL, 1 }, |
6 | { OPT_LEVELS_NONE, 0, NULL, 0 } |
7 | };
|
Falls fcommon anders abgehandelt wird (keine implizited Erzeugen von OPT_fcommon), funktioniert auf jeden Fall in Target Hook TARGET_OPTIMIZATION_OPTIONS flag_no_common = 1 zu setzen, ebenfalls in avr.c. Bei beiden Möglichkeiten hat dann ein -fcommon auf Kommandozeile höhere Priorität und überschreibt den Default.
Auch wenn ich mit meiner Bemerkung etwas nacheile: Common Blocks sind durchaus eine recht brauchbare Einrichtung, wenn man z.B. mehrere unabhängige Programm-Module hat, die zur Übersetzungszeit die Größe eines gemeinsamen Puffers festlegen sollen. Man definiert einfach in jedem Modul den Puffer mit der notwendigen Größe. Der Linker kombiniert dann alle Versionen zu einer Variablen mit der maximalen Größe. Dieser Trick ist vor allem in hierarchisch aufgebauten Libs sehr praktisch. Dem Problem mit unerwünschten Variablen-Kolisionen im Commonblock begegnet man am besten dadurch, daß man öffentlichen Variablen einen Modulspezifischen Präfix verpaßt - so haben das schon die Altvorderen im Assemblerzeitalter auch gemacht.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.