Forum: PC-Programmierung typedefs in h-File werden nicht erkannt


von Lief E. (kallisti)


Lesenswert?

Hallo

Ich habe ein grösseres Projekt, welches mehrere - von verschiedenen 
Leuten erstellte - Hardwarelibraries verwendet.
Mir fiel nun auf, dass in jeder dieser Libs typedefs verwendet werden 
(entweder wurden sie direkt implementiert oder als h-File eingebunden).
Ich dachte mir, es sei sinnvoll, alle diese typedefs in einem einzigen 
File zusammen zu nehmen. Das habe ich auch gemacht und das File 
LibDefines.h genannt.
Es ist so, dass ich ein Hauptprogramm habe (nennen wir es main.c) und 
darin binde ich meine Hauptlibrary (lib.h) ein.
Und in lib.h binde ich dann wiederum die oben erwähnten 
Hardware-Libraries (a.h/b.h/c.h) ein.
Also habe ich mein LibDefines.h einfach zuoberst in meiner Hauptlibrary 
lib.h eingebunden, sodass dem Compiler bevor er a.h/b.h/c.h aufruft, die 
typedefs schon bekannt sind.
Leider funktioniert das nicht, der Compiler (msp-gcc) zeigt solche 
Fehlermeldungen:

In file included from ../../Library/ff.c:76:
../../Library/ff.h:429: error: expected specifier-qualifier-list before 
'BYTE'
../../Library/ff.h:466: error: expected specifier-qualifier-list before 
'WORD'
Etc etc.

Ich interpretiere das so, dass die typedefs dem Compiler nicht bekannt 
sind.

Ich habe dann LibDefines.h direkt in a.h/b.h/c.h eingebunden (wobei 
LibDefines.h einen Include-Guard hat).
Dann funktioniert die Software fehlerfrei.

Ich verstehe jedoch nicht, warum es dann im ersten Fall nicht 
funktioniert.

Ich bedanke mich im voraus für Eure Hilfe!

von Karl H. (kbuchegg)


Lesenswert?

Lief Erickson schrieb:

> Ich verstehe jedoch nicht, warum es dann im ersten Fall nicht
> funktioniert.

Ohne ein bischen nachvollziehbaren Code wird dir da auch hier keiner 
helfen können.

Aber ein Tip:
Wenn ich mir nicht sicher bin, ob ein Header File überhaupt eingebunden 
wird, dann mach ich ganz gerne mal folgenden Test:

Ich provoziere im Header File einen Fehler.
Einfach am Anfang irgendeinen Text "hsdf8uzcinerwb" einfügen.

Die Erwartungshaltung ist:
Wenn dieses Header File eingebunden wird (egal über welche dubiosen 
Wege), dann muss ich den von mir provozierten Fehler beim Compilieren 
sehen. Kommt KEIN Fehler vom Compiler, dann kann ich sicher sein, dass 
dieses Header File nicht eingebunden wurde und mache mich auf die Suche, 
warum nicht. Das können dann zb irgendwelche #define / #ifdef 
Kombinationen sein, die diesen #include auslassen. Das können 
Namenskonflikte bei Include-Guards sein. Das kann alles mögliche sein.

Dieser 'Fehler provizier' Test ist meistens ziemlich wirkungsvoll, vor 
allen Dingen dann, wenn man dann anfängt den 'Fehler' zu verschieben um 
nachzuvollziehen, welcher Weg durch einen #ifdef Dschungel eigentlich 
genommen wird.

von Marwin (Gast)


Lesenswert?

Ohne den konkreten Code zu sehen, ist das reines Raetselraten. Abgesehen 
davon ist es eine kluge Strategie, dass jedes File selbst das included, 
was es braucht und nicht in irgendwelchen Implementationsfiles 
Headerfiles includet werden, damit andere, spaeter includete Headerfiles 
funktionieren - wer soll darueber langfristig den Ueberblick behalten?

von Lief E. (kallisti)


Lesenswert?

Also hier das erwähnte main:
1
// File:   13_Stoppuhr.c
2
// Date:   12.12.2009
3
4
#include <lib_v2.h>   // Hauptlib          
5
6
//---------------------------------------------------------------------------
7
//Hauptprogramm
8
//---------------------------------------------------------------------------
9
int main(void)
10
{
11
12
}

Lib_v2.h :
1
//#####################################################################
2
// Target....: TI MSP430F1611 microcontroller
3
// Date......: 2010.06.08
4
// Purpose...: Headerfile for Lib_v2.c. 
5
//######################################################################
6
7
//================================================================== includes
8
//------------------------------------------ compiler's include path 
9
#include <io.h>
10
#include <signal.h>
11
#include <stdio.h>
12
13
//--------------------- module headers for used modules defined in Hardware.h
14
#include <LibDefines.h>  //Lib mit den typedefs
15
#include <Hardware.h>    //Hier werden die unten geprueften defines gesetzt
16
17
//------------------------------------------------------------- TimerA module
18
#ifdef HwUSE_TIMER_A
19
  #include <LibTimerA.h>
20
#endif
21
  
22
//-------------------------------------------------- analog/digital converter
23
#ifdef HwUSE_ADC
24
  #include <LibAdc.h>
25
#endif
26
  
27
//-------------------------------------------------- digital/analog converter
28
#ifdef HwUSE_DAC
29
  #include <LibDac.h>
30
#endif
31
32
//-------------------------------------------------------------- UART1 module
33
#ifdef HwUSE_UART1
34
  #include <LibUart1.h>
35
#endif
36
37
//-------------------------------------------------------------- UART0 module
38
#ifdef HwUSE_UART0
39
  #include <LibUart0.h>
40
#endif
41
42
//-------------------------------------------------------- LCD display module
43
#ifdef HwUSE_LCD
44
  #include <LibLcd.h>  //Benoetigt LibDefines.h
45
#endif  
46
47
//-------------------------------------------------------- SD Card
48
#ifdef HwUSE_SDCard
49
  #include <ff.h>     //Benoetigt LibDefines.h
50
  #include <fat.h>    //Benoetigt LibDefines.h
51
#endif

LibDefines.h
1
//#####################################################################
2
// Target....: TI MSP430F1611 microcontroller
3
// Date......: 05.06.2012
4
// Purpose...: Global #defines and type definition in this file
5
//###########################################################################
6
#ifndef _LIBDEFINES
7
#define _LIBDEFINES
8
//******************************************************** global definitions
9
//======================================================= common data types
10
// Due to the fact that not every compiler treats the standard C datatypes
11
// the same way (e.g. unsigned short may be 8 bits wide on some compilers,
12
// 16 bits on others), it is useful to define own types, which can be made
13
// the same across all platforms. The code will get more portable.
14
//=========================================================================
15
                      
16
typedef unsigned char       BYTE;                         // 8 bits
17
typedef unsigned char       UCHAR;                        // 8 bits used for SD Card
18
19
typedef unsigned int        WORD;                         // 16 bits
20
typedef unsigned int        UINT;                         // 16 bits used for SD Card
21
typedef unsigned short      USHORT;                       // 16 bits used for SD Card
22
typedef unsigned short      WCHAR;                        // 16 bits used for SD Card
23
24
typedef unsigned long       DWORD;                        // 32 bits
25
typedef unsigned long       ULONG;                        // 32 bits used for SD Card
26
typedef unsigned long long  QWORD;                        // 64 bits
27
28
typedef char          SBYTE;                              // 8 bits signed
29
30
typedef int           INT;                                // 16 bits used for SD Card
31
typedef short         SWORD;                              // 16 bits signed           
32
typedef short         SHORT;                              // 16 bits used for SD Card
33
34
typedef long          SDWORD;                             // 32 bits signed                        
35
typedef long          LONG;                               // 32 bits used for SD Card
36
typedef long long     SQWORD;                             // 64 bits signed
37
38
#ifndef NULL
39
  #define NULL    ((void*)0)
40
#endif
41
42
//========================================================= boolean constants
43
typedef enum { FALSE = 0, TRUE } BOOL;
44
//==================================================== input/output constants
45
#define INPUT   0x00                             // set ports as input
46
#define OUTPUT  0xFF                             // set ports as output
47
48
#endif /*_LIBDEFINES */


Und in den Files LibLcd.h/ff.h und fat.h nichts eingebunden.

>Wenn ich mir nicht sicher bin, ob ein Header File überhaupt eingebunden
>wird, dann mach ich ganz gerne mal folgenden Test:
>Ich provoziere im Header File einen Fehler.
>Einfach am Anfang irgendeinen Text "hsdf8uzcinerwb" einfügen.

Das habe ich auch gemacht, er hat bei jeder Headerdatei, die ich 
modifiziert habe, eine Fehlermeldung gebracht.

>es eine kluge Strategie, dass jedes File selbst das included,
>was es braucht und nicht in irgendwelchen Implementationsfiles
>Headerfiles includet werden

Da geb ich Dir Recht, das macht eigentlich mehr Sinn.

Ich würde einfach gerne wissen, wo der Unterschied liegt, wenn ich das 
File wie oben einbinde oder halt einzeln bei jedem der drei Libraries.
Wenn der Compiler die Files überstetzt, dann kommt er ja im oberen Fall 
ziemlich schnell einmal zum LibDefines.h. Er sieht die typedefs und 
speichert diese (irgendwo?) ab. Warum sind dann diese den anderen 
h-Files so nicht bekannt. Wenn ich LibDefines.h jedoch in jedem File 
einzeln einbinde, dann geht der Compiler ja auch nur einmal hindurch 
(wegen dem Include-Guard) im Gegensatz zum ersten Fall funktioniert es 
jedoch.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Es ist so, dass ich ein Hauptprogramm habe (nennen wir es main.c) und
> darin binde ich meine Hauptlibrary (lib.h) ein.

Du solltest dringendst Deine Terminologie ändern. Es geht hier nicht 
um Libraries, sondern um Headerdateien oder meinetwegen 
"Includedateien".

Der Begriff "Library" aber ist ein feststehender Begriff mit einer 
feststehenden Bedeutung, wenn Du den falsch verwendest, kommt es zu 
Irritationen.


</pedanterie, wichtige>

von Karl H. (kbuchegg)


Lesenswert?

Lief Erickson schrieb:

> Ich würde einfach gerne wissen, wo der Unterschied liegt, wenn ich das
> File wie oben einbinde oder halt einzeln bei jedem der drei Libraries.

Keinen.
Da muss es noch irgendeine Zusatzbedingung geben, die du übersiehst und 
auf die hier keiner kommt.

Kann es sein, dass du deinen Include-Guard zb beim Compiler Aufruf 
vorbelegt hast?

von Lief E. (kallisti)


Lesenswert?

>Kann es sein, dass du deinen Include-Guard zb beim Compiler Aufruf
>vorbelegt hast?

Ich weiss nicht genau, was Du damit meinst.

Mein Makefile sieht so aus:
1
#################################################################### 
2
# Platform..: TI-MSP430
3
# Date......: 07.07.2009
4
# Input.....: The following commandline parameters are required for the
5
#             compile and build jobs. The examples use variables (%var%) as
6
#             they are provided by PsPad programming editor. This
7
#             commandline must be provided for build operations:
8
#
9
#             make JOB=%Ext% SOURCE=%Name%%Ext% TOOLS="D:\Program Files\MspGcc"
10
#
11
#             make.exe JOB=%Ext% SOURCE=%Name%%Ext% TOOLS=<MspGccPath>
12
#                      [DLAUTO=yes]
13
#
14
#             EXT=%Ext%           Is used for build operations. It is the
15
#                                 file extension of the active file in the
16
#                                 editor.
17
#
18
#             SOURCE=%Name%%Ext%  Is the name and extension of the active
19
#                                 file in the editor. It is used for single
20
#                                 file compilations.
21
#
22
#             TOOLS=<MspGccPath>  Root directory of MspGcc installation.
23
#                                 Must be enclosed in quotes if the path
24
#                                 contains spaces.
25
#
26
#             DLAUTO=yes          Tells the make job if the object file
27
#                                 shall be downloaded immediately after a
28
#                                 a successful build.
29
#
30
#             For non-compile or build jobs (makehex, makelst, download,
31
#             debug and clean) the syntax is
32
#
33
#             make.exe [makehex | makelst | download | debug | clean]
34
#
35
#             Note that these jobs can also perform a build operation,
36
#             depending on the job settings.            
37
#             
38
# Remarks...: The current path when executing this makefile has to be in
39
#             the folder, where the objects go (e.g. ./Obj). In PsPad, it
40
#             can be set in the compiler dialog, e.g. %ProjectDir%\Obj.
41
#############################################################################
42
43
#===================================================== customizable section
44
#-------------------project name, will also be the name of the output file
45
PROJECT = 13_stoppuhr_Dev3
46
47
#--------------------------- paths relative to object path (%ProjectDir%\Obj)
48
SRCPATH = ../Src/
49
BINPATH = ../Bin/
50
LSTPATH = ../Lst/
51
LIBPATH = ../../Library/                       
52
#---------------------------------- list of all main and library source files
53
MAINSOURCES = 13_Stoppuhr.c
54
LIBSOURCES  =  Lib_v2.c fat.c ff.c diskio.c LibLcd.c 
55
56
#---------------------------------- paths for executables and system includes
57
MSPINST = $(TOOLS)/
58
MSPINC  = "$(MSPINST)msp430/include"
59
MSPEXE  = $(MSPINST)Bin/
60
CC      = "$(MSPEXE)msp430-gcc"
61
RM      = rm.exe
62
63
#------------------------------------ COM port for iProg FTDI chip (COMx - 1)
64
BSLPORT = 4
65
66
#------------------------------------- automatic download on successful build
67
DLAUTO  = no
68
69
#================================================ end of customizable section
70
71
#------------------------------------------------------- environment settings
72
SOURCES  = $(MAINSOURCES) $(LIBSOURCES)
73
74
DEPSSRC  = $(addprefix $(SRCPATH), $(MAINSOURCES)) \
75
           $(addprefix $(LIBPATH), $(LIBSOURCES))
76
77
INCLUDES = -I $(SRCPATH) -I $(LIBPATH) -I $(MSPINC) 
78
79
VPATH    = $(SRCPATH) $(LIBPATH)
80
81
#---------------------------------------------------------- compiler settings
82
MCU     = msp430x1611
83
LDFLAGS = -mmcu=$(MCU)
84
CFLAGS  = -mmcu=$(MCU) $(INCLUDES) -g -O0 -Wall 
85
86
#======================================================== command line parser
87
# Call job depending on filename on commandline
88
#============================================================================
89
ifeq "$(suffix $(JOB))" ".c"
90
  EXEC = compile
91
92
endif
93
94
ifeq "$(basename $(JOB))" "makefile"
95
96
  ifeq "$(DLAUTO)" "yes"
97
    EXEC = download
98
  else
99
    EXEC = build
100
  endif    
101
102
endif
103
  
104
job: $(EXEC)
105
# Debug     @echo $(SOURCE): successJOB
106
#============================================================================
107
108
#============================================================== job 'compile'
109
# A single file gets compiled. The file is the active file in the editor.
110
#============================================================================
111
OBJECT = $(SOURCE:.c=.o)
112
113
compile: $(SOURCE)
114
  $(CC) $(CFLAGS) -c -o $(OBJECT) $<
115
  @echo $(SOURCE): success1 compile
116
#============================================================================
117
118
#================================================================ job 'build'
119
# The whole project gets compiled and linked
120
# Syntax: Either 'make.exe build' or 'make.exe job=%Ext%' with 'makefile'
121
#         as active file in the editor
122
#============================================================================
123
OBJECTS = $(SOURCES:.c=.o)
124
  
125
$(PROJECT): $(OBJECTS) 
126
  $(CC) $(LDFLAGS) $(OBJECTS) -o $(BINPATH)$(PROJECT).elf
127
  "$(MSPEXE)msp430-size" $(BINPATH)$(PROJECT).elf
128
  
129
$(SOURCES): 
130
  $(CC) $(CFLAGS) $< -o $@
131
132
build: $(SOURCES) $(PROJECT)
133
  @echo $(PROJECT): success2 Build
134
#============================================================================
135
136
#============================================================= job 'download'
137
# Download .elf file onto target. A successful build has to be done before.
138
# To check for this automatically, add 'build' to download: line.         
139
# Syntax: make.exe download
140
#============================================================================
141
download: build
142
  "$(MSPEXE)msp430-bsl" -c $(BSLPORT) -e --invert-test --invert-reset \
143
  $(BINPATH)$(PROJECT).elf
144
# Debug: rma wenn an dieser Stelle = Fehler.  @echo $(PROJECT): success3 Download build
145
#============================================================================
146
147
#============================================================== job 'makehex'
148
# Create .HEX file out of .ELF
149
# Syntax: make.exe makehex
150
#============================================================================
151
makehex: build
152
  "$(MSPEXE)msp430-objcopy" -O ihex $(BINPATH)$(PROJECT).elf \
153
  $(BINPATH)$(PROJECT).hex
154
  @echo $(PROJECT).hex created success6
155
#============================================================================
156
157
#============================================================== job 'makelst'
158
# Create .LST file out of .ELF
159
# Syntax: make.exe makelst
160
#============================================================================
161
LSTOBJ = $(SOURCES:.c=.o)
162
163
makelst: build
164
  "$(MSPEXE)msp430-objdump" -dSt $(LSTOBJ) >$(LSTPATH)$(PROJECT).lst
165
    @echo $(PROJECT).lst created
166
#============================================================================
167
168
#================================================================ job 'debug'
169
# Start Insight debugger
170
# Syntax: make.exe debug
171
#============================================================================
172
debug: build
173
  @echo loading...
174
  @cmd.exe /C start "gdbproxy" /MIN $(MSPEXE)Msp430-gdbproxy msp430 TIUSB
175
  @echo target remote localhost:2000 >gdb.ini
176
  @echo erase all >>gdb.ini
177
  @echo file $(BINPATH)$(PROJECT).elf  >>gdb.ini 
178
  @echo load $(BINPATH)$(PROJECT).elf  >>gdb.ini
179
  @echo break main >>gdb.ini
180
  @echo continue >>gdb.ini
181
  "$(MSPEXE)Msp430-insight" --command=gdb.ini  
182
  @del gdb.ini
183
  @taskkill /F /IM msp430-gdbproxy.exe
184
  
185
#================================================================ job 'clean'
186
# Delete all auto-generated files
187
# Syntax: make.exe clean
188
#============================================================================
189
clean:
190
  $(RM) *.o *.a43 dependencies.in \
191
  $(BINPATH)*.elf \
192
  $(BINPATH)*.hex \
193
  $(LSTPATH)*.lst
194
  @echo clean success4
195
#============================================================================
196
197
#=============================================================== dependencies
198
-include dependencies.in
199
dependencies.in:
200
  $(CC) -MM $(CFLAGS) $(DEPSSRC) >$@
201
  @echo dependencies update complete
202
#============================================================================
203
   
204
############################################################ EOF makefile

Ich habe schon das Gefuehl, dass es am Kompiliervorgang selber liegt. 
Ich weiss nur nicht genau, wie ich heraus finden kann, welches File er 
als erstes kompiliert und wie die Objectfiles dann linkt.

von Lief E. (kallisti)


Lesenswert?

Ich habe den Fehler gefunden, danke für die Hilfe und die Tips :)

von Karl H. (kbuchegg)


Lesenswert?

Lief Erickson schrieb:
> Ich habe den Fehler gefunden, danke für die Hilfe und die Tips :)

Und, was wars?
(Jetzt hast du mich neugierig gemacht)

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


Lesenswert?

Lief Erickson schrieb:
> Ich habe den Fehler gefunden, danke für die Hilfe und die Tips :)

Nun schmeiß deine altertümlichen Datentypen noch weg und ersetz
sie durch die C99-Pendants aus <stdint.h>.  Schließlich wurde gerade
der C11-Standard verabschiedet, da wäre es Zeit, sich zumindest an
den vorherigen mal zu gewöhnen ...

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.