Forum: Compiler & IDEs Problem mit globalen Array


von Norbert S. (norton)


Lesenswert?

Hallo Leute,

ich möchte folgendes realisieren:
1
main.c
2
3
.
4
.
5
uint16_t spg_tabelle[ MAX_U_VAUES ][3]={
6
  {890, 277, 225},   // 12,00 V   01
7
  {868, 278, 231},   // 11,75 V   02
8
  {853, 279, 230},   // 11,50 V   03
9
  .
10
  .
11
  .
12
  {366, 276, 445},   // 05,00 V   29
13
};
14
.
15
.
16
17
18
funk.c
19
20
extern uint16_t _spg_tabelle[ MAX_U_VAUES ][3];
21
.
22
.
23
24
void set_adc_value(void)
25
{
26
   int8_t i = 0;  
27
      for (i=0; i < MAX_U_VAUES; i++)     // Spannungstabelle durchsuchen
28
      {
29
      if (__adc_interrupt_value >= _spg_tabelle[i][0])       // Passenden Wert aus der Tabelle heraussuchen
30
      {
31
         _pwm_wert = _spg_tabelle[i][_pwm_spalte];                 // Wert Übergeben (_pwm_spalte entspricht ein / aus Impuls)
32
         break;
33
      }
34
   }
35
}

ich bekomme folgende Fehlermeldung:
C:\..\default/../funk.c:129: undefined reference to `_spg_tabelle'

Meine Fragen:

Wie sieht der richtige Umgang mit einem globalen 2 Dimensionalen Array 
aus?
Gibt es eine bessere Möglichkeit eine Kreuztabelle zu erstellen (kann je 
Projekt verschieden lang sein), vielleicht als Konstanten oder Defines?

Danke Norton

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Vielleicht solltest du mal deine Affinität zu führenden Unterstrichen
überprüfen...  In erster Näherung sind Namen mit führenden Unter-
strichen für dich als Benutzer tabu -- sie sind für Compiler und
Bibliothek vorbehalten.  (In zweiter Näherung gibt es Ausnahmen von
dieser Regel, aber die sind weniger wichtig.)

Kommt hinzu, dass du dir offenbar nicht mal merken kannst, ob du
nun vor deinen Namen einen Unterstrich davor setzt oder nicht,
und dass du es dadurch mal so, mal so geschrieben hast.  Kein
Wunder also, dass der Linker das nicht zusammen popeln kann.

von Matthias L. (Gast)


Lesenswert?

>In erster Näherung sind Namen mit führenden Unter-
>strichen für dich als Benutzer tabu -- sie sind für Compiler und
>Bibliothek vorbehalten.

Inwieweit?

Ich dachte bisher immer, dass doppelte Unterstriche für lib-interne 
Variablen verwendet werden.

Ich verwende einfache Unterstriche (zB _u8TempFor) immer als Synonym für 
lokale Variablen.

von nixversteh (Gast)


Lesenswert?

>>       if (__adc_interrupt_value >= _spg_tabelle[i][0]) ...
             ^^
             !!
wird dort auch munter mißbraucht. Allerdings interessiert mich dazu auch 
Jörg's (allzeit kompetente) Erklärung der Sachlage. Weil, so richtig 
wissen tue ich es auch nicht.

von Norbert S. (norton)


Lesenswert?

Jörg Wunsch wrote:
> Vielleicht solltest du mal deine Affinität zu führenden Unterstrichen
> überprüfen...  In erster Näherung sind Namen mit führenden Unter-
> strichen für dich als Benutzer tabu -- sie sind für Compiler und
> Bibliothek vorbehalten.  (In zweiter Näherung gibt es Ausnahmen von
> dieser Regel, aber die sind weniger wichtig.)

Das wußte ich leider nicht das die für mich tabu sind. Habe mir vor 
langer Zeit und anderer Programmiersprache angewöhnt globale Variablen 
mit "__" und lokale mit "_" zu markieren. Muss ich mir halt etwas neues 
einfallen lassen.

> Kommt hinzu, dass du dir offenbar nicht mal merken kannst, ob du
> nun vor deinen Namen einen Unterstrich davor setzt oder nicht,
> und dass du es dadurch mal so, mal so geschrieben hast.  Kein
> Wunder also, dass der Linker das nicht zusammen popeln kann.

Das mit der Namensinkonsistenz ist mir anscheinend beim zusammenkopieren 
passiert.
Ich habe die Namen jetzt im Code alle ohne unterstriche und durchgängig 
gemacht und bekomme trotzdem folgende Fehler:

C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:123: 
undefined reference to `spg_tabelle'
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:123: 
undefined reference to `spg_tabelle'
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:129: 
undefined reference to `spg_tabelle'
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:129: 
undefined reference to `spg_tabelle'
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:129: 
undefined reference to `spg_tabelle'
lib_mv_schalten.o:C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_s 
chalten.c:129:  more undefined references to `spg_tabelle' follow

von Michael Wilhelm (Gast)


Lesenswert?

Hast du im Modul lib_mv_schalten.c auch das extern spg_tabelle geändert?
                                                   ^
MW

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Norbert S. wrote:

> Das mit der Namensinkonsistenz ist mir anscheinend beim zusammenkopieren
> passiert.
> Ich habe die Namen jetzt im Code alle ohne unterstriche und durchgängig
> gemacht und bekomme trotzdem folgende Fehler:

Dann wäre noch deine Linker-Kommandozeile interessant.  Offenbar
versuchst du, nur main.o zu linken nicht aber funk.o (oder
genau andersrum? dein copy&paste verursacht mehr Unklarheiten
als es beseitigt).

Die tatsächlichen Regeln, welche Bezeichner mit Unterstrichen wo
zugelassen sind, sind leider etwas komplizierter.  Die entsprechenden
Bezeichner sind gemäß Standard "für die Implementierung reserviert",
das heißt, sie dürfen von Compiler uns Systembibliothek (das ist in
erster Linie die Bibliothek, die benötigt wird, um den C-Sprachstandard
zu erfüllen) für ihre eigenen Zwecke benutzt werden.  Wenn -- wie
bei AVR-GCC und avr-libc -- diese beiden Komponenten der Sprach-
implementierung nicht aus einer Hand kommen, dann müssen diese beiden
sich intern absprechen, wer welche Bezeichner für welche Zwecke
benutzt.  Für GCC-globale Dinge gibt in diesem Falle GCC einfach vor,
was er benutzt (das ist aber relativ wenig, da gehören so Dinge wie
_GNUC_ dazu), für die AVR-spezifischen Teile des Compiler arbeiten
die zuständigen GCC-Entwickler wiederum eng mit den avr-libc-
Entwicklern zusammen bzw. (Anatolij Sokolov) sogar in Personalunion.

Inwieweit man weitere allgemeine Bibliotheken (also beispielsweise
X11 unter Unix, diverse Grafikbibliotheken, allgemeine Kompressions-
algorithmen wie zlib, etc. pp.) auch als "zur Implementierung
gehörig" rechnen kann, sodass diese eigene Teilnamensräume aus dem
Unterstrich-Bereich für sich beanspruchen können, sei jetzt mal
dahin gestellt.  Im strengen Sinne des Standards dürfen sie nicht,
andererseits haben sie praktisch dasselbe Problem wie die C-Bibliothek
(Vermeidung von Namenskollision mit dem Anwenderprogramm).  Jedoch
für reine Bibliotheken auf der Applikationsseite, die von der gleichen
Gruppe von Entwicklern gepflegt werden wie die endgültige Applikation,
trifft dieser Status (Bestandteil der "Implementierung" zu sein)
nun wirklich nicht mehr zu.

Hier nun nochmal eine Kurzfassung der Regeln:

Bezeichner, die mit zwei Unterstrichen beginnen, sind immer für
die Implementierung reserviert, egal in welchem Kontext sie
auftauchen.  Teilweise kann die Implementierung natürlich diese
Namen dokumentieren.  So kann man sich auf _GNUC_ verlassen beim
GCC, und man kann mit _asm_ arbeiten, um unabhängig von der
-std= Option den Inline-Assembler zu benutzen.  Die avr-libc
dokumentiert __STDIO_FDEVOPEN_COMPAT_12, mit der man die stdio-
Funktionen rückwärtskompatibel zur Version 1.2.x benutzen kann,
usw. usf.

Gleiches trifft zu auf Namen, die mit einem Unterstrich, gefolgt
von einem Großbuchstaben beginnen.

Namen, die auf Ebene einer Quelldatei mit einem Unterstrich beginnen,
sind ebenfalls reserviert.  Das betrifft alle Namen von Variablen,
Datentypen einschließlich struct/union/enum und Makros (#define).

Das lässt Namen übrig, die mit einem Unterstrich beginnen, gefolgt
von einem Kleinbuchstaben für die folgende Verwendung:

. lokale Variablen in Funktionen
. struct/union/enum-Bezeichnungen in C (nicht in C++, da sie dort
  zugleich einen Typnamen bilden) sowie deren Elemente

von Norbert S. (norton)


Lesenswert?

> Dann wäre noch deine Linker-Kommandozeile interessant.  Offenbar
> versuchst du, nur main.o zu linken nicht aber funk.o (oder
> genau andersrum? dein copy&paste verursacht mehr Unklarheiten
> als es beseitigt).

Das wäre die Ausgabe die ich bekomme:
(mein main.c ist das "__S8Dusche.c" file und das funk.c ist das 
"lib_mv_schalten.c" file)

Bitte weitere Kommentare zu den Unterstrichen nur wenn sie relevant 
sind.

Code ist sonst wie im Beispiel oben mit gleichen namen und ohne 
Unterstriche.

Build started 2.9.2008 at 10:07:12
avr-gcc.exe 
-I"C:\Daten\Projekte\S8\CPrg\S8Dusche\..\..\..\AVR-C-Compiler\Programme\ 
_LIB"  -I"C:\Daten\Projekte\S8\CPrg\S8Dusche\."  -mmcu=atmega1281 -Wall 
-gdwarf-2 -std=gnu99 
-DF_CPU=4000000
UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums 
-MD -MP -MT __S8Dusche.o -MF dep/__S8Dusche.o.d  -c  ../__S8Dusche.c

../__S8Dusche.c: In function 'main':
../__S8Dusche.c:32: warning: unused variable 'spg_tabelle'
avr-gcc.exe -mmcu=atmega1281 -Wl,-Map=S8Dusche.map __S8Dusche.o 
lib_Print_S8-6-12.o lib_allgemein.o lib_dip_switch.o lib_adc_messung.o 
lib_ir_impuls.o lib_wertetabelle.o lib_spi_messung.o lib_mv_schalten.o 
lib_ventilator.o lib_uart.o lib_platinen_test.o li
b_fade.o     -o S8Dusche.elf

lib_mv_schalten.o: In function `set_adc_value':
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:124: 
undefined reference to `spg_tabelle'
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:124: 
undefined reference to `spg_tabelle'
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:130: 
undefined reference to `spg_tabelle'
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:130: 
undefined reference to `spg_tabelle'
C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_schalten.c:130: 
undefined reference to `spg_tabelle'
lib_mv_schalten.o:C:\Daten\Projekte\S8\CPrg\S8Dusche\default/../lib_mv_s 
chalten.c:130:  more undefined references to `spg_tabelle' follow
make: *** [S8Dusche.elf] Error 1
Build failed with 6 errors and 1 warnings...

von Stefan E. (sternst)


Lesenswert?

> ../__S8Dusche.c: In function 'main':
> ../__S8Dusche.c:32: warning: unused variable 'spg_tabelle'

Du hast spg_tabelle versehentlich als lokale Variable von main 
definiert, statt als globale Variable.
Wieder mal ein gutes Beispiel dafür, dass nicht nur die Fehlermeldungen 
interessant sind, sondern auch die Warnungen.

von Norbert S. (norton)


Lesenswert?

Stefan Ernst wrote:
>> ../__S8Dusche.c: In function 'main':
>> ../__S8Dusche.c:32: warning: unused variable 'spg_tabelle'
>
> Du hast spg_tabelle versehentlich als lokale Variable von main
> definiert, statt als globale Variable.
> Wieder mal ein gutes Beispiel dafür, dass nicht nur die Fehlermeldungen
> interessant sind, sondern auch die Warnungen.

Das wars! Jetzt funktionierts.
So ein blöder Fehler, aber ich habe ja immerhin viele andere Sachen 
dabei gelernt.

Danke auch allen.

von Simon K. (simon) Benutzerseite


Lesenswert?

"Gängig" ist zum  Beispiel die Prefixe
g_ für globale Variablen und
m_ für member-Variablen (C++)

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.