Forum: PC-Programmierung Probleme mit den bekanntmachen von Funktionen in Header bei C++


von Philip (Gast)


Lesenswert?

Hallo ihr lieben,

ich habe leider bei meinen Hobbyprogrammieren ein Problem mit den 
Headerdateien.

Ich habe leider aus speicherplatzgründen eine Klasse in einzelne 
Funktionen auflösen müssen, da der Arbeitsspeicher und Flashspaicher 
nicht ausreichend ist.
Desshalb möchte ich in den namensraum std einfach ein paar Funktionen 
haben.
Innerhalb der Funktionen lese und schribe ich mehrmals in vershiedene 
Variablen aus den Nahmensraum.

Leider schaffe ich es nicht die Variablen und Funktionen in einer Header 
Datei zu hinderlegen.
Die Beispiele und tutorials haben bei mir auch nichts geholfen, da sie 
lediglich das Problem im Kontext von Klassendefinitionen abhandeln.

Die Fehlermeldungen sind:
../Core/Src/Parser.cpp:1411:29: error: call of overloaded 
'IsNumeric(char*&)' is ambiguous
../Core/Src/Parser.cpp:1438:35: error: call of overloaded 
'strToU32(char*&)' is ambiguous
../Core/Src/Parser.cpp:1443:38: error: call of overloaded 
'IsNumeric(char*&)' is ambiguous
../Core/Src/Parser.cpp:1468:31: error: call of overloaded 
'IsNumeric(char*&)' is ambiguous
../Core/Src/Parser.cpp:1469:36: error: call of overloaded 
'strXToU32(char*&)' is ambiguous
../Core/Src/Parser.cpp:1474:39: error: call of overloaded 
'IsNumeric(char*&)' is ambiguous

Hat jemand ein Tipp wie ich die Fehlermeldungen beseitigen kann?
Leider hat es mit extern deklaratonen wie in C üblich nicht fuktioniert.
Genau so wie wenn ich versuche die Probleme mit std:: auf zu lösen.
Dann bekomme ich 'multiple definition' Fehler.

Parser.cpp
1
#include <content_xml.hpp>
2
#include <Parser.hpp>
3
#include <stdint.h>
4
#include <stdlib.h>
5
#include <string.h>
6
7
using namespace std;
8
9
extern volatile uint32_t Memory[1024];
10
11
12
void ParserChar(char *ptr, uint16_t Len){
13
  //...
14
}
15
16
void ParserMem(uint32_t *ptr){
17
  //...
18
}
19
20
21
uint8_t StartParserXml(char *ptr, uint16_t Len){
22
    //...
23
    return 1;
24
}
25
26
uint8_t StartParserByte(uint32_t *ptr){
27
    //...
28
    return 1;
29
}
30
31
ClContent_xml** contentAdd(uint16_t inkrement){
32
    //...
33
}
34
35
uint8_t StartCheckXml(void){
36
  //...
37
    return 1;
38
}
39
40
uint8_t StartGenerateByte(uint32_t* ptr, uint16_t MaxLen){
41
  //...
42
    return 1;
43
}
44
45
uint32_t getByte(uint16_t i){
46
    //...
47
    return Value;
48
}
49
50
uint8_t NumData(char* ptr){
51
    //...
52
    return Nummer;
53
}
54
55
uint8_t IsNumeric(char* ptr){
56
    //...
57
    return 0;
58
}
59
60
uint8_t strToU8(char* ptr){
61
    //...
62
    return Val;
63
}
64
65
uint16_t strToU16(char* ptr){
66
    //...
67
}
68
69
uint32_t strToU32(char* ptr){
70
    //...
71
    return Val;
72
}
73
74
uint32_t strXToU32(char* ptr){
75
    //...
76
    return Val;
77
}
78
79
uint16_t* strToU16Array(char* ptr){
80
    uint16_t Val = 0;
81
    uint8_t Num = 0;
82
    uint8_t st = 0;
83
    uint16_t *Array, *LArray;
84
    char *Sptr;
85
    Sptr = ptr;
86
87
    // Anzahl der Zahlen ermitteln
88
    do{
89
        switch(*ptr){
90
        case '0':
91
        case '1':
92
        case '2':
93
        case '3':
94
        case '4':
95
        case '5':
96
        case '6':
97
        case '7':
98
        case '8':
99
        case '9':
100
            if((st & 0x02) == 0x00){
101
                Num++;
102
                st |= 0x02;
103
            }
104
            break;
105
        case ' ':
106
        case ',':
107
            if((st & 0x02) == 0x02){
108
                st = (st & ~0x02);
109
            }
110
            break;
111
        default:
112
            st |= 0x01;
113
            break;
114
        }
115
        ptr++;
116
    }while((st & 0x01) == 0);
117
118
    Array = new uint16_t[Num];
119
    LArray = Array;
120
121
    for(uint8_t i = 0; i < Num; i++){
122
        while((*Sptr == ' ') || (*Sptr == ',')){
123
            Sptr++;
124
        }
125
126
        *LArray = strToU16(Sptr);
127
128
        //printf("\n%i, Wert: %i, Adresse: 0x%x", i, *LArray, LArray);
129
130
        while(IsNumeric(Sptr)){
131
            Sptr++;
132
        }
133
        LArray++;
134
    }
135
    return Array;
136
}
137
138
uint32_t* strToU32Array(char* ptr, uint8_t Num){
139
    uint32_t Val = 0;
140
    uint8_t st = 0;
141
    uint32_t *Array, *LArray;
142
    char *Sptr;
143
    Sptr = ptr;
144
145
    Array = new uint32_t[Num];
146
    LArray = Array;
147
148
    for(uint8_t i = 0; i < Num; i++){
149
        // Leerzeichen ignurieren
150
        while(*ptr == ' '){
151
            ptr++;
152
        }
153
        if(1 == IsNumeric(ptr)){
154
            *LArray = strToU32(ptr);
155
            LArray++;
156
            do{
157
                ptr++;
158
            }while(1 == IsNumeric(ptr));
159
        }
160
        else{
161
            return Array;
162
        }
163
    }
164
    return Array;
165
}
166
167
uint32_t* strXToU32Array(char* ptr, uint8_t Num){
168
    uint32_t Val = 0;
169
    uint8_t st = 0;
170
    uint32_t *Array, *LArray;
171
172
    Array = new uint32_t[Num];
173
    LArray = Array;
174
175
    for(uint8_t i = 0; i < Num; i++){
176
        // Leerzeichen ignurieren
177
        while((*ptr == ' ') || (*ptr == ',')){
178
            ptr++;
179
        }
180
181
        if((1 == IsNumeric(ptr))){
182
            *LArray = strXToU32(ptr);
183
            LArray++;
184
            do{
185
                ptr++;
186
            }while((1 == IsNumeric(ptr)) || (*ptr == 'x') || (*ptr == 'X'));
187
        }
188
        else{
189
            return Array;
190
        }
191
    }
192
    return Array;
193
}
194
195
uint16_t setByteU8(uint8_t Value, uint16_t Inkrement){
196
    //...
197
    return Inkrement + 1;
198
}
199
200
uint16_t setByteU16(uint16_t Value, uint16_t Inkrement){
201
    //...
202
    return Inkrement + 2;
203
}
204
205
uint16_t setByteU32(uint32_t Value, uint16_t Inkrement){
206
    //...
207
    return Inkrement + 4;
208
}
209
210
uint16_t setByte(void){
211
    // MemByte in das Flash schreiben
212
    return 0;
213
}

Parser.hpp
1
#ifndef PARSER_H
2
#define PARSER_H
3
4
#include <stdint.h>
5
#include <content_xml.hpp>
6
#include <loopdef.hpp>
7
#include <trigger.hpp>
8
9
namespace std{
10
  void ParserChar(char*, uint16_t);
11
  void ParserMem(uint32_t*);
12
13
  // Funktionsprototypen
14
  uint8_t pstringp(char*, uint16_t);
15
  uint8_t GetValue(void);
16
17
  // Variablen
18
  ClContent_xml **contentXml;
19
  uint8_t contentXml_Load;
20
21
  uint8_t StartParserXml(char*, uint16_t);
22
  uint8_t StartCheckXml(void);
23
  uint8_t StartParserByte(uint32_t*);
24
  uint8_t StartGenerateByte(uint32_t*, uint16_t);
25
  uint32_t *BytePtr;
26
27
  uint8_t NumData(char*);
28
  uint8_t IsNumeric(char*);
29
  uint8_t strToU8(char*);
30
  uint16_t strToU16(char*);
31
  uint32_t strToU32(char*);
32
  uint32_t strXToU32(char*);
33
34
  uint16_t* strToU16Array(char*);
35
  uint32_t* strToU32Array(char*, uint8_t);
36
  uint32_t* strXToU32Array(char*, uint8_t);
37
38
  char StrGreet[30];
39
40
  // Variablen
41
  char* StringPtr;
42
  uint16_t StringLen;
43
44
  // Prototypen
45
  ClContent_xml **contentAdd(uint16_t);
46
  uint32_t getByte(uint16_t);
47
  uint16_t setByteU8(uint8_t, uint16_t);
48
  uint16_t setByteU16(uint16_t, uint16_t);
49
  uint16_t setByteU32(uint32_t, uint16_t);
50
  uint16_t setByte(void);
51
52
  uint32_t MemByte;
53
54
  ClLoopdef **StmLoop;
55
  uint8_t StmLoopLoad;
56
  ClTrigger **StmTrigger;
57
  uint8_t StmTriggerLoad;
58
}
59
#endif // PARSER_H

Vielen Dank und Frohes neues Jahr

Philip

von Mombert H. (mh_mh)


Lesenswert?

Philip schrieb:
> Desshalb möchte ich in den namensraum std einfach ein paar Funktionen
> haben.
Das ist nicht erlaubt. Aber was hält dich davon ab einen eigenen auf zu 
machen?

Philip schrieb:
> using namespace std;
Das solltest du dir ganz ganz schnell abgewöhnen.

von Oliver S. (oliverso)


Lesenswert?

Die Fehler stecken in den Zeilen ab 1411. Dein Quellcode zeigt die 
nicht. Dazu schreibst du von Problemen mit Header-Dateien, zeigst aber 
eine .cpp
Wie soll man da helfen?

Und als letztes steht über jedem Beitrag in Fett:

> Wichtige Regeln - erst lesen, dann posten!
> Groß- und Kleinschreibung verwenden
> Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Bevor du jetzt hier 2000 Zeilen in das Textfeld ballern willst.

Oliver

: Bearbeitet durch User
von Philip (Gast)


Lesenswert?

Ich habe hier nicht nur eine *.cpp Datei gekürz eingestellt sondern 
darunter auch die *.hpp Datei (ungekürzt) also erst lesen.

Die Fehlermeldungen habe ich leider vergessen an den gekürzten Inhalt 
anzupassen...
Inzwischen habe ich wie von  Mombert H vorgeschagen das ganze in ein 
eigenen Namensraum verschoben.
Dadurch haben sich die Fehlermeldungen geändert:
../Core/Src/Parser.cpp:126:32: error: call of overloaded 
'strToU16(char*&)' is ambiguous
../Core/Src/Parser.cpp:130:29: error: call of overloaded 
'IsNumeric(char*&)' is ambiguous
../Core/Src/Parser.cpp:153:30: error: call of overloaded 
'IsNumeric(char*&)' is ambiguous
../Core/Src/Parser.cpp:154:35: error: call of overloaded 
'strToU32(char*&)' is ambiguous
../Core/Src/Parser.cpp:158:38: error: call of overloaded 
'IsNumeric(char*&)' is ambiguous
(Die Zeilennummern sind an den gekürzten Code angepasst).

von Rolf M. (rmagnus)


Lesenswert?

Philip schrieb:
> Hat jemand ein Tipp wie ich die Fehlermeldungen beseitigen kann?

In deiner hpp-Datei sind die Funktionen im Namespace, in der cpp-Datei 
sind sie außerhalb davon.

Philip schrieb:
> Ich habe hier nicht nur eine *.cpp Datei gekürz eingestellt sondern
> darunter auch die *.hpp Datei (ungekürzt) also erst lesen.

Es ging darum, dass du so langen Code nicht inline in dein Posting 
stecken sollst, sonst als separate Dateien anhängen.

von Philip (Gast)


Lesenswert?

Bei mir verschwinden die Fehler wenn ich die Funktionen mit dem Schema 
'Namensraum::Funktionsname(){}' definiere.
Klingt ja Logisch...

Leider habe bekomme ich statt dessen 'multiple definition of' Fehler:

c:\st\stm32cubeide_1.3.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.e 
xternaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_2.0.0.2021053113 
46\tools\arm-none-eabi\bin\ld.exe: 
./Core/Src/maincpp.o:(.bss._ZN6Parser14StmTriggerLoadE+0x0): multiple 
definition of `Parser::StmTriggerLoad';
./Core/Src/Parser.o:(.bss._ZN6Parser14StmTriggerLoadE+0x0): first 
defined here

Für die folgenden Variablen in einer Funktion aus maincpp.cpp.
In der Datei habe ich die Datei Parser.hpp includiert.
1
Parser::contentXml = nullptr;
2
Parser::contentXml_Load = 0;
3
Parser::BytePtr = nullptr;
4
Parser::StringPtr = nullptr;
5
Parser::StringLen = 0;
6
Parser::MemByte = 0;
7
Parser::StmLoop = nullptr;
8
Parser::StmLoopLoad = 0;
9
Parser::StmTrigger = nullptr;
10
Parser::StmTriggerLoad = 0;

Die einzige Definition von den Variablen habe habe ich in der 
Headerdatei Parser.hpp gemacht.
Header guards sind ja gundlegender Standart bei der Programmierung mit C 
und C++.

Unter C hätte ich in der Headerdatei in ähnlichen Kontext einfach den 
Prototypen extern vorangestellt.
Ähnliches habe ich unter C++ noch nicht gesehen...

von Mombert H. (mh_mh)


Lesenswert?

Philip schrieb:
> Die einzige Definition von den Variablen habe habe ich in der
> Headerdatei Parser.hpp gemacht.
> Header guards sind ja gundlegender Standart bei der Programmierung mit C
> und C++.
>
> Unter C hätte ich in der Headerdatei in ähnlichen Kontext einfach den
> Prototypen extern vorangestellt.
> Ähnliches habe ich unter C++ noch nicht gesehen...

Du solltest dir ein Ordentliches Buch zulegen und lesen. Der Unterschied 
zwischen Definition und Deklaration ist ein ziemlich wichtiges Konzept 
in C und C++.

von Oliver S. (oliverso)


Lesenswert?

Philip schrieb:
> Die einzige Definition von den Variablen habe habe ich in der
> Headerdatei Parser.hpp gemacht.
> Header guards sind ja gundlegender Standart bei der Programmierung mit C
> und C++.

Ja, und daher wird pro Objektdatei die fragliche Funktion nur einmal 
erzeugt. Was für den Linker dann immer noch viel zu viele sind, so daß 
der sich zu Recht beschwert.

Da du aber immer ich nicht den Code zeigst, der zu den Fehlermeldungen 
passt, musst du halt weiter rätseln.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Philip schrieb:
> Die einzige Definition von den Variablen habe habe ich in der
> Headerdatei Parser.hpp gemacht.

Da gehört sie aber nicht hin. Dort darf nur die Deklaration hin, nicht 
die Definition.

> Header guards sind ja gundlegender Standart bei der Programmierung mit C
> und C++.

Die helfen nur gegen mehrfaches Einbinden in der selben .cpp-Datei.

> Unter C hätte ich in der Headerdatei in ähnlichen Kontext einfach den
> Prototypen extern vorangestellt.

Genau das musst du in C++ auch tun.

von Philip (Gast)


Lesenswert?

Hallo,
Sorry habe die Begriffe Definition und Deklaration verwechselt...
Peinlich wenn man das den Kollegen immer vorhält wenn ihnen das 
passiert.

Ich habe mich in C++ schon eingelesen, aber mir in den Fall nicht viel 
herleiten können.
Leider habe ich bei der Suche im Internet keine für mich 
nachvollziehbare Beispiele hierfür gefunden, daraufhin habe ich nach 
lösungen von ähnlichen Problemen in den KiCad Code gesucht, aber auch da 
nichts gefunden...

Wenn ich wie im letzten Beitrag vorgeschlagen in dem Headerfile das 
schlüsselwort extern einfüge steigt die Anzahl der Fehler bei den 
versuch zu Kompilieren auf 42 an.
Für die Variablen ist jeweils die Fehlermeldung "undefined reference to 
'Parser::Variablenname'".

Grüße

Philip

von Oliver S. (oliverso)


Lesenswert?

Nun ja, irgendwo muß die Definition auch einmal ohne extern auftauchen.

Oliver

von Philip (Gast)


Lesenswert?

Ok das ist dann doch ein Rückschritt zu C...
Da reichen die extern Deklarationen in den Headerfiles einfach aus.

Grüße

Philip

von Dirk B. (dirkb2)


Lesenswert?

Philip schrieb:
> Ok das ist dann doch ein Rückschritt zu C...
> Da reichen die extern Deklarationen in den Headerfiles einfach aus.

Nein.
In einer .C Datei muss die Variable definiert werden.
Sonst gibt es ja nur Deklarationen.

von Rolf M. (rmagnus)


Lesenswert?

Philip schrieb:
> Ok das ist dann doch ein Rückschritt zu C...
> Da reichen die extern Deklarationen in den Headerfiles einfach aus.

Nein. Auch in C muss die Variable definiert sein. "extern" heißt, dass 
die Variable irgendwo anders definiert ist. Damit das funktioniert, muss 
sie auch irgendwo anders definiert sein. Das ist in C und C++ gleich.

von Oliver S. (oliverso)


Lesenswert?

Philip schrieb:
> Ich habe mich in C++ schon eingelesen, aber mir in den Fall nicht viel
> herleiten können.

Das Thema ist allergrundglegenstes C/C++-Basiswissen. Und das kommt 
alleine hier im Forum so oft, da ist die Forensuche anscheinend 
überfordert.

Ich habe daher mal für dich bei google inc in Kalifornien angefragt, ob 
die das Thema mal auf Microcontroller.net recherchieren können. Sie 
konnten...

https://www.google.com/search?q=c+header+globale+variablen+extern+site:www.mikrocontroller.net&client=firefox-b-d&sa=X&ved=2ahUKEwiD37HT9LX1AhXuhv0HHeMsBSkQrQIoBHoECAYQBQ&biw=1536&bih=739&dpr=1.25

Oliver

: Bearbeitet durch User
von Philip (Gast)


Lesenswert?

Ok vielen Dank euch!

Ich das ist jetzt der Punkt bei dem es bei mir gehangen hat...

Ich weis das in C streng genommen das auch so ist mir Deklaration und 
extern Deklaration, wobei bei mir sich die Compiler noch nicht beschwert 
haben wen ich lediglich extern deklarationen erstellt habe.

Beruflich habe ich mit den Sprachen C und Matlab M-Script / Simulink 
zutuhen.
Bei C eigendlich sogar in zeimliche Tiefe da ich regelmäsig statische 
Code Analysen auswerte...

Grüße

Philip

von Oliver S. (oliverso)


Lesenswert?

Philip schrieb:
> Beruflich habe ich mit den Sprachen C und Matlab M-Script / Simulink
> zutuhen.
> Bei C eigendlich sogar in zeimliche Tiefe da ich regelmäsig statische
> Code Analysen auswerte...

Das klingt jetzt dann doch etwas überraschend. Was für Produkte sind das 
denn?

Oliver

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.