Forum: Mikrocontroller und Digitale Elektronik #defines in jeder Datei nutzen??


von Darkleon (Gast)


Lesenswert?

Hallo!

Ich habe folgendes Problem....

Ich programmiere in C für einen PIC 18F4550. Ich habe mehrere *.c Files 
in meinem Projekt und alle benutzen zwei globale Variablen, die in main 
deklariert sind. Soweit funktionert das auch.
In main sind die Variablen wie folgend deklariert:
1
unsigned int STabelle[33];
2
unsigned int WTabelle[33];

In den anderen *.c Files natürlich mit dem Zusatz
1
extern ...

Da die Variablen Arrays sind möchte ich jetzt nur einmal die Größe 
ändern, damit das dann überall übernommen wird. Sonst müsste ich ja in 
jedem File die Größe wieder manuell ändern.

Dachte mir ich mach ne *.h File und schreib folgendes rein:
1
#define STSIZE   28  
2
#define WTSIZE   28

Diese includiere ich dann in jeder Datei und schreib bei meinen globalen 
Variablen
1
 unsigned int STabelle[STSIZE];
2
unsigned int WTabelle[WTSIZE]
Nur bekomm ich immer beim compilieren einen "syntax error". Und gemeint 
ist die Zeile, in der ich die Variablen deklariere.
Kann mir jemand dabei helfen?? Trotz alledem, dass ich die h-Datei mit 
den #defines inkludiert habe, übernimmt der Compiler nicht die Werte an 
den Platz, wo sie hinsollen.

Bin für jeden Tip dankbar.

MfG Darkleon

von Sven P. (Gast)


Lesenswert?

Kann nicht sein, was du machst ist eigentlich korrekt. (Abgesehen davon, 
dass du die 'extern'-Deklarationen eigentlich auch noch in den Header 
packen könntest, spart Tipparbeit)

Also:
1. genaue Fehlermeldung posten
2. vollständigen Quelltext zeigen.

von Darkleon (Gast)


Lesenswert?

Also meine H- Datei heißt "PICsetup.h"

Da drin steht folgendes:
1
#define STSIZE   28  
2
#define WTSIZE   28

Die main sieht folgendermaßen aus (der relevante Teil):
1
#include "PICsetup.h"
2
#include <p18f4550.h>
3
4
//PUBLIC VARIABLES//
5
unsigned int STabelle[STSIZE];
6
unsigned int WTabelle[WTSIZE];
7
8
/******PROCEDURE ********/
9
void main (void)
10
{
11
12
}

Die Fehlermeldung (MPLAB V8.30)
main.c:12:Error: syntax error

Ich weiß eben auch nicht mehr weiter, wieso der Compiler die defines 
nicht übernimmt, denn in den Einstellungen sind die "Inlcude" Pfade 
richtig angegeben..

MfG

von skorpionx (Gast)


Lesenswert?

Versuch  das:

extern unsigned int *STabelle;
extern unsigned int *WTabelle;

von Uhu U. (uhu)


Lesenswert?

Darkleon schrieb:
> Die Fehlermeldung (MPLAB V8.30)
> main.c:12:Error: syntax error

Kommt die Fehlermeldung tatsächlich bei der schließenden Klammer von 
Main?

Kommentiere mal versuchsweise die ganze main aus und compiliere. Wenn 
der Fehler dann weg ist, gefällt ihm die main nicht.

(Du wirst dann zwar einen Linkerfehler bekommen, aber das ist erst mal 
egal.)

von Uhu U. (uhu)


Lesenswert?

skorpionx schrieb:
> extern unsigned int *STabelle;
> extern unsigned int *WTabelle;

Damit werden die Arrays zwar deklariert, aber nicht definiert. Das endet 
dann mit einem Linkerfehler...

von skorpionx (Gast)


Lesenswert?

>Damit werden die Arrays zwar deklariert, aber nicht definiert. Das endet
>dann mit einem Linkerfehler...

Hier sind die schon definiert:

//PUBLIC VARIABLES//
unsigned int STabelle[STSIZE];
unsigned int WTabelle[WTSIZE];

/******PROCEDURE ********/
void main (void)
{

}

von Uhu U. (uhu)


Lesenswert?

skorpionx schrieb:
>>Damit werden die Arrays zwar deklariert, aber nicht definiert. Das endet
>>dann mit einem Linkerfehler...
>
> Hier sind die schon definiert:

Dann mußt du mal erklären, was du mit deinem Posting oben gemeint hast.

von skorpionx (Gast)


Lesenswert?

>Ich programmiere in C für einen PIC 18F4550. Ich habe mehrere *.c Files...

Die Variablen dürfen nur in einem File definiert werden und in anderen
mit dem zusatz extern deklariert.
Dem Compiler stört  das bei der externem deklkarationen noch die
Grösse (STSIZE...)steht.

von alex (Gast)


Lesenswert?

Bei "void main" meckert der Compiler nicht? Sollte es nicht "int main" 
sein?

von Mark B. (markbrandis)


Lesenswert?

alex schrieb:
> Bei "void main" meckert der Compiler nicht? Sollte es nicht "int main"
> sein?

Eigentlich sollte main() einen Rückgabewert haben. Auch wenn das bei 
Embedded-Programmierung mit der typischen Endlosschleife nicht so 
richtig Sinn ergibt.

von Ralph (Gast)


Lesenswert?

sieh dir mal die Schreibweise fürs Define an.
Es gibt da zwischen den Compilern unterschiede.
Einige wollen ein "=" vor dem Wert, es gibt auch die Variante mit ";" am 
Ende.
Sollte aber in der Beschreibung des Compilers stehen.

von Uhu U. (uhu)


Lesenswert?

Ralph schrieb:
> sieh dir mal die Schreibweise fürs Define an.
> Es gibt da zwischen den Compilern unterschiede.
> Einige wollen ein "=" vor dem Wert, es gibt auch die Variante mit ";" am
> Ende.

Wenn es ein C-Compiler ist, dann bestimmt nicht. Die Syntax der 
#define-Direktiven ist korrekt.

Ich tippe darauf, daß der Compiler sich an der Signatur von main stört. 
Das quittieren manche mit einem Syntaxfehler, andere tolerieren es.

Daß der Fehler offenbar bei der schließenden Klammer von main kommt, 
deutet darauf, daß er sich an main verschluckt hat.

von Darkleon (Gast)


Lesenswert?

Hallo!

Also der Compiler mekert nicht bei main, sondern bei der Deklaration von
1
unsigned int STabelle[STSIZE];

Ich habe ja in der Header Datei "nur" STSIZE definiert und den Wert 
zugewiesen. Die eigentliche Variablendefinition ist die, die kurz vor 
main steht.

In den anderen Source Dateien sind die globalen Variablen natürlich mit 
"extern" gekennzeichnet.

Wenn ich die globalen Variablen in der Header Datei definiere. Also nach
1
#define STSIZE 26
2
[c/]
3
kommt dann 
4
[c]
5
unsigned int STabelle[STSIZE];

und in main diese auch extern angebe, dann mekert er auch bei der 
gleichen Zeile....

Keine Ahnung was da schief läuft..

MfG

von Uhu U. (uhu)


Lesenswert?

Kommentiere mal die main aus und compiliere neu.

Wenn dann der Fehler weg ist, bzw ein Linkerfehler kommt, dann versuchs 
mal so:
1
int main(int argc, char **argv) {
2
3
}

von Darkleon (Gast)


Lesenswert?

Hab die main auskommentiert, und jetzt bringt der Compiler folgendes:

Error [1105] symbol 'STSIZE' has not been defined
Error [1219] integer constant expected
Error [1105] symbol 'WTSIZE' has not been defined
Error [1219] integer constant expected

Als ich ohne diesen Versuch mein Programm kompiliert habe, also mit
1
unsigned int STabelle[26]
2
unsigned int WTabelle[26]

hat alles funktioniert. Nur fand ich es eben als lästig, dass ich in 
jedem c-file den Wert ändern musste, wenn z.B.: das Array um ein Feld 
vergrößert werden musste.
Deshalb wollte ich das eigentlich jetzt nur einmal definieren und alle 
c-files (inkl.main) bekommen den neuern Wert von der Header Datei.

Aber das will nicht wirklich...

MfG

von Darkleon (Gast)


Lesenswert?

Noch als Zusatz:

Benutz den C18-Compiler. Hatte mit
1
void main (void)
noch nie Probleme.

Wenn ich
1
int main (void)
angebe, dann bringt mir der Compiler folgendes:

Warning [2103] default startup code expects main function declared as 
'void main (void)'

Aber wie schon gesagt, an der main liegt es nicht. Irgendwo gibts 
Probleme die defines an die richtige Stelle zu stellen.

MfG

von Uhu U. (uhu)


Lesenswert?

Poste mal die .c und .h Files. Es ist bestimmt irgendwas saudummes, was 
man so nicht sieht. C-Compiler sind zuweilen etwas hinterhältig...

Was du noch machen kannst: Sieh mal nach, ob der Compiler eine Option 
hat, mit der man die Ausgabe des Preprocessors auf Datei ausgeben kann. 
Dann siehst du, was aus deinen #defines geworden ist.

von Walter (Gast)


Lesenswert?

>Die Fehlermeldung (MPLAB V8.30)
>main.c:12:Error: syntax error

1) Zeile 12 ist die schließende Klammer von main??

2) es reicht wenn du in einem File die arrays definierst
und im anderen mit
extern int array[]
deklarierst, da brauchts keine Größenangabe. Feldgrenzen werden ja weder 
vom Compiler noch zur Laufzeit überprüft

>Error [1105] symbol 'STSIZE' has not been defined
3) dann versuch doch mal das define direkt vor die Definition in den 
main.c File zu schreiben

von Darkleon (Gast)


Lesenswert?

Im Post 3 hab ich schon alles hergezeigt :) Mehr besteht nocht nicht, da 
ich das komplette Projekt erst angefangen hab und die c-files schon 
vorher geschrieben hab.

Wenn ich es so schreib
1
#include "PICsetup.h"
2
#include <p18f4550.h>
3
4
#define STSIZE   28  
5
#define WTSIZE   28  
6
7
//PUBLIC VARIABLES//
8
unsigned int STabelle[STSIZE];
9
unsigned int WTabelle[WTSIZE];
10
11
/******PROCEDURE ********/
12
13
void main (void)
14
{
15
16
}
dann compiliert er alles und gibt das OK. Nur wäre dann die PICsetup.h 
sinnlos und die defines wären dann für die anderen c-files wieder 
unsichtbar. Das heißt ich müsste die wieder überall definieren und hätte 
überhaupt keine "Erleichterung".

von HildeK (Gast)


Lesenswert?

Ich kann zwar nichts zur Lösung beitragen, aber deine Vorgehensweise ist 
imho absolut korrekt.

Beispiel:
in der STDLIB.H eines alten DOS-Compilers steht z.B.
1
#define _MAX_PATH  260  /* max. length of full pathname */
2
#define _MAX_DRIVE  3  /* max. length of drive component */
3
#define _MAX_DIR  256  /* max. length of path component */
usw.,
und diese Konstanten können in jedem Modul verwendet werden - genauso 
wie du es machst.

Einzig die Tatsache, dass deine Include-Datei nicht bei den 
System-Includes steht, ist ein Unterschied.
Probier doch mal mit einer Kopie deiner PICsetup.h im entsprechenden 
Verzeichnis diese Variante:
#include <PICsetup.h>

Alternativ könnte noch ein im Editor nicht sichtbares Sonderzeichen in 
den beiden #define-Zeilen stören - habe ich auch schon erlebt.

PS. Ich bin nur Gelegenheitsprogrammierer für eigene, kleine 
Hilfsmittelchen :-)

von Darkleon (Gast)


Lesenswert?

C12 ist schon die Zeile, wo "STabelle" definiert wird. Hab nur die 
Leerzeilen und Kommentare hier im Forum weggelöscht.

Also das mit der deklaration "extern unsigned int STabelle[]" wusste ich 
noch nicht, zumindest nicht mit der leeren Klammer. Sonst sind die 
Arrays in jedem file, die die benötigt mit extern gekennzeichnet.

Das muss ich gleich mal versuchen...

MfG

von Uhu U. (uhu)


Lesenswert?

Darkleon schrieb:
> Im Post 3 hab ich schon alles hergezeigt :) Mehr besteht nocht nicht, da
> ich das komplette Projekt erst angefangen hab und die c-files schon
> vorher geschrieben hab.

Das ist wie gesagt was saudummes und wenn du die Orginalfiles nicht 
posten willst, mußt du eben selbst suchen.

von Darkleon (Gast)


Lesenswert?

@ uhu

Wie gesagt, mehr gibts noch nicht. ich hab nicht mal die c-files in das 
Projekt inkludiert. Wollte das eben nur mal mit den #define's versuchen, 
da ich mir dadurch einiges an Schreibarbeit ersparen könnte.

MfG

von Uhu U. (uhu)


Lesenswert?

Hab leider keine Glaskugel, die mir sagt, was du genau gemacht hast. 
Also such selbst.

von Darkleon (Gast)


Lesenswert?

uhu, ich weiß nicht, was du jetzt hast?

Ich hab alles geschrieben, und mehr besteht noch nicht. Hab noch keine 
Source Dateien dem Projekt hinzugefügt und bei main mekert der Compiler 
wegen der Definition.
Mehr gibts auch nicht, dazu braucht man keine Glaskugel....

Das mit den leeren Klammern funktioniert :) Werd das Projekt jetzt mal 
zusammenstellen und dann schauen ob alles passt ;)

Hab auch versucht die "PICsetup.h" in den "Include"-Ordner zu opieren 
und mit < > einzubinden, aber da ensteht der gleiche Fehler, der schon 
von Anfang an war.

Jetzt versuch ich mal alles mit den [] zu machen und schau, ob das dann 
funktioniert. Das wäre ja im Grunde die gleiche Sache, die ich mit den 
defines vorhatte:)

Nochmals Danke an alle für die schnelle und informative Hilfe.

Wünsche allen schon mal eine gute Nacht :D
Nochmals Danke!!!

Mfg Darkleon

von Uhu U. (uhu)


Lesenswert?

@ Darkleon

Was ich habe? 25 Jahre Erfahrung mit C.

Du wärst nicht der Erste, der meint alles richtig gemacht zu haben und 
trotzdem eine Fußangel in seinem Quelltext hat, die man aus zweiter Hand 
nie findet.

von Walter (Gast)


Lesenswert?

ist zwar schön dass dir mein Tipp mit den leeren Klammern hilft,
aber das ist nur kurzfristig bis du wieder Mal ein define brauchst

Was Uhu meint ist die 2 betreffenden Dateien als Anhang zu posten damit 
man wirklich sieht was drin steht.
Das würde Dir auch langfristig mmehr helfen

von Wolfgang Mües (Gast)


Lesenswert?

Häng doch bitte mal in der Include-Datei mit den beiden #defines drin 
eine leere Zeile am Ende an.

Alter Anfängerfehler! #include ist eine reine Textersetzung.

Also eine include-Datei test.h mit folgendem Inhalt:

#define TEST 10 (ohne Zeilenende hier!)

included in folgende Sourcecodedatei

#include <test.h>
void main()

wird nach dem Preprozessor zu:
#define TEST 10 void main()

und schon hast Du Deinen Syntax error.

Gruß

WM

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

Wolfgang Mües schrieb:
...
> Alter Anfängerfehler! #include ist eine reine Textersetzung.
>
> Also eine include-Datei test.h mit folgendem Inhalt:
>
> #define TEST 10 (ohne Zeilenende hier!)
>
> included in folgende Sourcecodedatei
>
> #include <test.h>
> void main()
>
> wird nach dem Preprozessor zu:
> #define TEST 10 void main()

Auch beliebt:
1
#define KONSTANTE 123;
2
int foo[KONSTANTE];

> und schon hast Du Deinen Syntax error.

Falk

von termite (Gast)


Lesenswert?

moin

vermutung von mir, deine PICsetup.h wird nicht angezogen. sollte 
eigentlich ein Warning schmeissen "Include not found" oder so. also die 
log ausgabe noch mal genau anschauen, ggf das loglevel / warning level 
des compilers hochschrauben.

Uhrsache für die nichtgefundene PICsetup.h falscher oder fehlender 
Include path. falsche schreibweise, mehrer solcher dateien, und es wird 
die falsche angezogen.

alternative falsch gesetzte Includ gards aber ich vermute mal das die 
noch gar nicht drinnen sind.

von faustian (Gast)


Lesenswert?

Ist es wirklich ausgeschlossen, dass das in deinem Setup direkt an den 
Compiler, unter Umgehung des Präprozessors, geht?

Sonst jag es doch erstmal durch den Prä und guck Dir an was wirklich 
hinten rauskommt...

von Christoph (Gast)


Lesenswert?

Prüf doch mal nach ob am Ende jeder Datei (also nicht nur die Header, 
auch und vor allem die C-Files) eine neue, leere Zeile steht. Ist eine 
Weile her das ich mit dem C18 gearbeitet habe, aber ich meine mich zu 
erinnern das der bei diesen Sachen sehr zickig sein konnte.

von Mark B. (markbrandis)


Lesenswert?

Eigentlich sollte er dann "no newline at end of file" oder so anzeigen - 
eigentlich...

http://gcc.gnu.org/ml/gcc/2003-11/msg01568.html

von Karl H. (kbuchegg)


Lesenswert?

1
#include "PICsetup.h"
2
#include <p18f4550.h>

Zieh mal das Systemheader-File vor dein eigenes.
1
#include <p18f4550.h>
2
#include "PICsetup.h"

Sollte in deinem Fall eigentlich keinen Unterschied machen, aber wer 
weiß. Ist auch logischer so: Zuerst wird das System definiert, dann 
kommen deine eigenen Deklarationen und dann geht der Code los.

von MeinerEiner (Gast)


Lesenswert?

Einfach lassen... oder ihm erklären, wie man das Feld "Dateianhang" und 
die Schalftläche "Durchsuchen" verwendet.

von Darkleon (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

@MeinerEiner
Danke, aber ich weiß schon wie man Dateien anhängt. Keine Sorge..

Also ich hab gestern noch versucht die beiden Dateien auf einem anderen 
Rechner zu compilieren. Und da hats funktioniert.

Hab jetzt auf diesem Rechner das Projekt nochmals neu angelegt (mal nur 
mit diesen zwei Dateien) und nun funktionierts auch hier ?!? Keine 
Ahnung wieso das alte Projekt so gezickt hat.

Dachte mir ich kapier die defines in C überhaupt nicht mehr ;)

Hab die beiden Dateien angehängt. Hab eigentlich nichts verändert, nur 
wie gesagt ein neues Projekt erstellt.

Nochmals Danke an alle für die schnelle und kompetente Hilfe!

MfG Darkleon

von MeinerEiner (Gast)


Lesenswert?

Datentypen definiert man normalerweise nicht mit #define sondern mit 
typedef. Müsste sich zwar aufs gleiche rausgehen, wenn der Precompiler 
das ersetzt, aber drauf verlassen würd ich mich nicht.

von Uhu U. (uhu)


Lesenswert?

Derlei Konstruktionen haben auch das Potential zu veritablen Fußangen:
1
#define Init()  TRISA = 0b00000011; TRISC = 0x00; TRISD = 0x00; \
2
    LATA = 0x00; LATC = 0x00; LATD = 0x00;

Wenn man sowas meint unbedingt per #define machen zu müssen, dann doch 
bitte so:
1
#define Init()  do { TRISA = 0b00000011; TRISC = 0x00; TRISD = 0x00; \
2
    LATA = 0x00; LATC = 0x00; LATD = 0x00; } while(0)

Dann führen nämlich Konstukte wie dieses nicht mehr automatisch ins 
Abseits:
1
if (bedingung)
2
    Init();

Der Optimierungspaß des Compilers schmeißt den Code wieder raus, der von 
do ... while(0) generiert wird.

von Darkleon (Gast)


Lesenswert?

Hi uhu!

Danke für den Tip, aber wieso es intelligenter ist "do..while" zu 
verwenden versteh ich jetzt nicht ganz.
Init() kommt bei mir nur einmal ganz am Anfang von main vor, damit die 
Register gesetzt werden. Das mache ich nicht von einer Bedingung 
abhängig.
Hab mir diesen Stil wahrscheinlich von microchip abgeschaut, da die das 
auch immer in ihren Projekten verwenden. Wenn ich einfach das setzen der 
Bits an den Anfang von main schreibe ist es sicherlich einfacher, da der 
weg über #define nicht gemacht wird.

Aber nochmals zu Deinem Vorschlag. Die Schleife wird ja nur einmal 
durchlaufen, da ja die Bedinung in while nicht stimmt, oder? Kannst Du 
mir sagen, wieso das so sinvoller wäre? Lerne ja gerne dazu:)

MfG Darkleon

von Mr Tannnoy (Gast)


Lesenswert?

Du schreibst in deinem Headerfile:

#define STSIZE   28
#define WTSIZE   28


Ich würde mal schreiben:

const int STSIZE = 28;
const int WTSIZE = 28;

Es sind Konstanten. Es sind Integer-Werte.

Das ist es doch, was doch brauchst, oder?

von Uhu U. (uhu)


Lesenswert?

Darkleon schrieb:
> Danke für den Tip, aber wieso es intelligenter ist "do..while" zu
> verwenden versteh ich jetzt nicht ganz.
> Init() kommt bei mir nur einmal ganz am Anfang von main vor, damit die
> Register gesetzt werden. Das mache ich nicht von einer Bedingung
> abhängig.

Defines schreibt man häufig in Headerfiles und die guckt man dan i.d.R. 
nicht mehr so oft an. Dann erinnert man sich, daß es eine Funktion XYZ() 
gibt, die was bestimmtes macht, das man mal eben brauchen kann, wenn 
eine bestimmte Bedinung erfüllt ist... und schon ist es passiert: Mein 
Programm macht was, was völlig unmöglich ist und ein paar Stunden 
Fehlersuche.

Und das nur, weil man beim Verfassen dieses Macros mal wieder nicht vom 
Daumen zum Zeigefinger gedacht hat...

Das Problem ist, daß man bestrebt ist, ausgetesteten Code 
wiederzuverwenden, um sich die Zeit zu sparen, die entsprechende 
Funktionalität nochmal zu implementieren.

Wenn solcher wiederverwendeter Code unsauber geschrieben ist, kann man 
böse Überraschungen erleben...

> Aber nochmals zu Deinem Vorschlag. Die Schleife wird ja nur einmal
> durchlaufen, da ja die Bedinung in while nicht stimmt, oder? Kannst Du
> mir sagen, wieso das so sinvoller wäre? Lerne ja gerne dazu:)

Ja, aber der Unterschied ist eben, daß mit dem do ... while unter einem 
if der gesamte Block bedingt ausgeführt wird, während ohne das do ... 
while nur das erste Statement des #defines bedingt und der Rest 
unbedingt ausgeführt wird und man das dem Aufruf nicht ansieht.

#defines werden vom Preprozessor abgearbeitet, bevor der Compiler den 
Quelltext sieht. Wenn der den Namen eines definierten Symbols erkennt, 
dann kopiert er an seiner Stelle - evtl. nach einer textuellen 
Parametersubstitution - den Text aus dem #define ein.

Dieses do ... while(0) ist ein Trick, um den definierten Text 
syntaktisch als Statement zu verpacken und damit eine tückische 
Fehlerquelle zu beseitigen, die sich bei Benutzung des Preprozessors 
gerne unbemerkt einschleicht.

Es gibt Programmierer, die von der Benutzung von #define wegen solcher 
Fallstricke generell abraten. In der Tat könntest du in deinem Beispiel 
auch sehr gut ohne auskommen:

Die Konstanten kann man als enum-Tags (z.B. in einen Header) schreiben:
1
enum { STSIZE=28, WTSIZE=28 };

Dein INIT() kannst du, ohne dir irgendwas zu vergeben, als normale 
Funktion schreiben. Viele moderne C-Compiler kopieren kleine 
parameterlose Funktionen am Aufrufort als Maschinencode ein, statt sie 
per call aufzurufen.

Wie MeinerEiner oben schon geschrieben hat, kann man Datentypen per 
typedef definieren. Du kannst also wirklich ohne #define zurecht kommen.


Nachtrag: Die modernere (C++?) Variante der enum-Methode ist die von Mr 
Tannnoy oben beschriebene.

von HildeK (Gast)


Lesenswert?

>Es sind Konstanten. Es sind Integer-Werte.

>Das ist es doch, was doch brauchst, oder?

Schon, aber die brauchen dann auch extra Speicherplatz auf dem Target. 
Bei #define wird der String 'STSIZE' durch den String '28' beim 
Preprocessing ersetzt.

Er hat es durchaus sinnvoll gemacht und das Problem war ja auch gelöst - 
leider ohne dass man die Ursache genau ergründen konnte.

von Uhu U. (uhu)


Lesenswert?

HildeK schrieb:
> Schon, aber die brauchen dann auch extra Speicherplatz auf dem Target.
> Bei #define wird der String 'STSIZE' durch den String '28' beim
> Preprocessing ersetzt.

Zumindest C++ reserviert keinen Speicherplatz dafür. Ob C das auch so 
macht, weiß ich im Moment nicht.

von yalu (Gast)


Lesenswert?

Uhu Uhuhu schrieb:

> HildeK schrieb:
>> Schon, aber die brauchen dann auch extra Speicherplatz auf dem
>> Target. Bei #define wird der String 'STSIZE' durch den String '28'
>> beim Preprocessing ersetzt.
>
> Zumindest C++ reserviert keinen Speicherplatz dafür.

Sofern es der Compiler wegoptimiert. Der GCC tut dies von -O1 aufwärts.

> Ob C das auch so macht, weiß ich im Moment nicht.

In C hat das 'const' eine andere Bedeutung wie in C++, da geht das
gewünschte Konstrukt
1
const int n=5;
2
int a[n];

für statische a überhaupt nicht. Deswegen nimmt man in C für Konstanten
meist Makros, während in C++ mit const definierte Konstanten der bessere
Stil sind. Der Enum-Trick geht in beiden Sprachen, ist aber eher ein
Hack, da Enums, wie der Name schon andeutet, eigentlich für ganz andere
Dinge vorgesehen sind.

von termite (Gast)


Lesenswert?

moin

eine konstante variable sollte auf jedem C / C++ compiler eine Datenwort 
im Konstant area der ausgabe datei erzeugen. das bedeutet, das die 
Konstante
1. Speicherplatz im konstant area der ausgabe datei belegt, sollte in 
der map datei ersichtlich sein
2. dadurch eine indirekte addressierung ausgelöst werden kann. ein 
register wird nicht direkt mit dem wert initallisiert, sondern erst der 
wert von der adresse gelesen. dauert somit länger
3. gefahr das const mal zu vergessen, oder falsch zu setzen. ändert 
nichts am ablauf des Programmes, nur ist das dann eine vorinitallisierte 
variable, die zur laufzeit geändert werden kann, und beim startup erst 
initallisiert werden umss.

kann durch aus sein, dass kompiler das wegoptimieren können. nur ob man 
darauf vertrauen kann, ...

und zu dem lustigen do while(0) konstuckt.
1
#define Init()  do { TRISA = 0b00000011; TRISC = 0x00; TRISD = 0x00; \
2
    LATA = 0x00; LATC = 0x00; LATD = 0x00; } while(0) 
3
4
#define Init2() { TRISA = 0b00000011; TRISC = 0x00; TRISD = 0x00; \
5
    LATA = 0x00; LATC = 0x00; LATD = 0x00; }

Init2 sollte auch ohne du while(0) geraffel genau das gleiche bewirken. 
ausnahme. der kompiler ist dermassen verkorkst, das er das mit den {} 
nicht sauber gebacken bekommt.

oder man läst kein if,else, ... ohne ein nachfolgendes{} stehen. mach 
ich selbst wenn ich nur ner variable bedingt eine konstante zuweise.
1
if ( doInit )
2
{
3
  init2();
4
}
5
6
if ( a != b)
7
{
8
   x = a;
9
}
10
else
11
{
12
   x = b;
13
}
14
15
 x = (a!=b)?a:b; // macht das gleiche nur ohne if else

von Uhu U. (uhu)


Lesenswert?

termite schrieb:
> moin
>
> eine konstante variable sollte auf jedem C / C++ compiler eine Datenwort
> im Konstant area der ausgabe datei erzeugen. das bedeutet, das die
> Konstante
> 1. Speicherplatz im konstant area der ausgabe datei belegt, sollte in
> der map datei ersichtlich sein
> 2. dadurch eine indirekte addressierung ausgelöst werden kann. ein
> register wird nicht direkt mit dem wert initallisiert, sondern erst der
> wert von der adresse gelesen. dauert somit länger
> 3. gefahr das const mal zu vergessen, oder falsch zu setzen. ändert
> nichts am ablauf des Programmes, nur ist das dann eine vorinitallisierte
> variable, die zur laufzeit geändert werden kann, und beim startup erst
> initallisiert werden umss.

Dir ist bekannt, daß weder C noch C++ dynamische Arrays kennt? Falls für 
eine const-Variable in C++ Speicher allokiert wird - was ich nicht 
glaube - dann wird dessen Inhalt garantiert nicht für die Bestimmung von 
Arraygrenzen benutzt.

> und zu dem lustigen do while(0) konstuckt.
>
1
> #define Init()  do { TRISA = 0b00000011; TRISC = 0x00; TRISD = 0x00; \
2
>     LATA = 0x00; LATC = 0x00; LATD = 0x00; } while(0)
3
> 
4
> #define Init2() { TRISA = 0b00000011; TRISC = 0x00; TRISD = 0x00; \
5
>     LATA = 0x00; LATC = 0x00; LATD = 0x00; }
6
> 
7
>
>
> Init2 sollte auch ohne du while(0) geraffel genau das gleiche bewirken.
> ausnahme. der kompiler ist dermassen verkorkst, das er das mit den {}
> nicht sauber gebacken bekommt.
>
> oder man läst kein if,else, ... ohne ein nachfolgendes{} stehen. mach
> ich selbst wenn ich nur ner variable bedingt eine konstante zuweise.
>
1
> if ( doInit )
2
> {
3
>   init2();
4
> }

Und genau hier ist der Knackpunkt: init2() sieht aus, wie ein 
Funktionsaufruf, ist aber keiner - genau dieses Wissen hast du genutzt, 
als du schnell einen Block drumrum geschrieben hast...

Die Erfahrung sagt, daß schon nach relativ kurzer Zeit solche 
Implementierungsdetails nicht mehr unbedingt präsent sind und bei der 
nächsten Änderung rasselt irgendeiner in diese Falle und keiner merkts, 
bis irgendwas Schlimmes passiert. Dann kann man sich dumm und dämlich
debuggen, weil derlei Fehler nur im ASM-Modus des Debuggers 
nachzuvollziehen sind.

von Darkleon (Gast)


Lesenswert?

Hi!

@ Mr Tannnoy

Wenn ich Deinen Vorschlag benutze, so erzeuge ich ja zwei neue 
Variablen, die wieder Speicherplatz benötigen, oder? Vor allem will ich 
ja zur Laufzeit die Arraygröße nicht ändern.

Im Grunde will ich nur die Arraygröße einmal angeben müssen (in der 
Header Datei) und alles Funktionen wissen bescheid, wie groß die beiden 
Arrays sind und können damit arbeiten. Wie groß diese tatsächlich sind 
weiß ich jetzt eben noch nicht, denn während der programmierung kann 
sich noch vieles ändern (andere Sichtweise, neue Ideen, usw..)
Daher hab ich das mit define gelöst.

Dass ich auch die globalen Variablen in einer Headerdatei anlegen und 
dann in der jeweiligen Funktion inkludieren kann wusste ich bis jetzt 
noch nicht :) (Bin ja noch ziemlich am Anfang mit C und kenn daher die 
Tricks noch nicht). Ich glaub so werd ich das auch machen, da ich sie 
dann nur einmal ändern muss, und falls ich statt "int" ein "char" Array 
benutze (wegen Speicherplatz) brauch ich das so ja auch nur einmal 
ändern:) zu 90 Prozent muss ich nur Statusbits (0-1) ablegen, aber C 
kennt leider den Datentyp "boolean" nicht. Sensoren usw arbeiten dann 
auch mit 8-Bit Auflösung und das genügt für mein Vorhaben locker aus.
Deshalb wollte ich das alles so schnell wie möglich geändert haben.

Alles andere hier ist mir noch leider etwas zu hoch (die letzten 
Beiträge von uhu, yalu, usw..) aber ich lerne gerne dazu. (will mich ja 
mal wirklich auskennen, was ich mache und was es für Möglichkeiten 
gibt).

Nochmals Danke an alle!!

Ihr habt mir wirklich super weitergeholfen und mir viele Verbesserungen 
gezeigt.

MfG Darkleon

von Sven P. (Gast)


Lesenswert?

C kennt sehr wohl einen Boolean-Datentyp, ab C99. Der taugt allerdings 
wenig zum Speicherplatz sparen, denn er belegt normalerweise einen 
'int'.

C kennt auch 'dynamische' Alloziierung, zumindest in diesem Sinne:
1
size_t len = strlen(irgendein_string);
2
char string_kopie[len + 1];
3
memcpy(string_kopie, irgendein_string, len + 1);

von Uhu U. (uhu)


Lesenswert?

Sven P. schrieb:
> C kennt sehr wohl einen Boolean-Datentyp, ab C99. Der taugt allerdings
> wenig zum Speicherplatz sparen, denn er belegt normalerweise einen
> 'int'.
>
> C kennt auch 'dynamische' Alloziierung, zumindest in diesem Sinne:
>
1
> size_t len = strlen(irgendein_string);
2
> char string_kopie[len + 1];
3
> memcpy(string_kopie, irgendein_string, len + 1);
4
>

Den Code hast du aber garantiert noch nichtmal compiliert... Wir hatten 
es von Arrays im Sinn von
1
   int array[5];

Die sind und bleiben unveränderlich und die Arraygrenze wird zur 
Laufzeit implizit in den Stack-Allokierungscode eingebaut, bzw. für 
globale Arrays nur in einem Datensegment reserviert und nacher nicht 
mehr verwendet, es sei denn, man hat sie irgendwo definiert, oder 
berechnet sie explizit, z.B. durch Konstruktionen wie diese:
1
#define arraysize(x)   (sizeof x / sizeof x[0])

Im Übrigen ist von der Benutzung von dynamischen Speicherbereichen auf 
kleinen µCs unbedingt abzuraten.

von Sven P. (Gast)


Lesenswert?

Ja.

von Uhu U. (uhu)


Lesenswert?

Hast du meinen Edit gesehen?

von termite (Gast)


Lesenswert?

at Uhu Uhuhu:

bei der statischen definition von arrays wo es hier ja darum ging, ist 
das richtig. da dies ja schon zu kompilzeit definiert wird.

trotzdem ist es eine Variable, die selbst wenn sich nicht weiter benutzt 
wird. erst der linker kann dann entscheiden, ob er sie haben will oder 
nicht.

die Konstante für die Arraygrösse wird wenn man sie schon mal hat 
meistens auch noch für andere sachen verwendet, als nur für 
Arraydefinition: schleifen bedingungen, Ich hab da wohl etwas 
weitergedacht als nur bis zur definition.
1
const unsigned int BUFFER_LENGTH = 255u;
2
3
unsigned char buffer[BUFFER_LENGTH];
4
5
for (i = 0; i < BUFFER_LENGTH; i++)
6
{
7
   buffer[i] = i; 
8
}


und zum init2(). auch im macro ist ein block definiert. ich hab es im 
prinzipt doppelt abgesichert. einaml beim IF einmal im macro. das do 
while(0) emfinde ich für überflüssig, ausser es hatte einen speziellen 
grund, damit die block klammern nicht vom präprozessor oder sonst 
jemanden verschluckt werden.

das gleiche gilbt eigentlich auch für normale defines. die sollten auch 
geklammert werden.
1
#define HEAD 5
2
#define STRUKTSIZE 40
3
#define BUFFER1 HEAD + STRUCTSIZE /* kann zu fehlern führen */
4
#define BUFFER2 (HEAD + STRUCTSIZE)
5
6
unsigned char buffer1[4*BUFFER1]; // 4 * 5 + 40 falsch
7
unsigned char buffer2[4*BUFFER2]; // 4 * (5 + 40) richtig

von Uhu U. (uhu)


Lesenswert?

termite schrieb:
> und zum init2(). auch im macro ist ein block definiert. ich hab es im
> prinzipt doppelt abgesichert. einaml beim IF einmal im macro. das do
> while(0) emfinde ich für überflüssig, ausser es hatte einen speziellen
> grund, damit die block klammern nicht vom präprozessor oder sonst
> jemanden verschluckt werden.

Die Idee zu dem do ... while(0)-Trick ist, aus dem Macro-Rumpf ein 
Statement zu machen, nicht ein Compoundstatement. Damit hat es 
syntaktisch dieselben Eigenschaften, wie der Aufruf einer void-Funktion.

Die Methode ist übrigens eine schon ziemlich alte Empfehlung des 
C-Normierungskommitees.

> das gleiche gilbt eigentlich auch für normale defines. die sollten auch
> geklammert werden.
>
>
1
> #define HEAD 5
2
> #define STRUKTSIZE 40
3
> #define BUFFER1 HEAD + STRUCTSIZE /* kann zu fehlern führen */
4
> #define BUFFER2 (HEAD + STRUCTSIZE)
5
>
6
> unsigned char buffer1[4*BUFFER1]; // 4 * 5 + 40 falsch
7
> unsigned char buffer2[4*BUFFER2]; // 4 * (5 + 40) richtig
8
>

Genau. Der Preprozessor bietet viele Möglichkeiten, Fehler einzubauen, 
die man dem Quelltext nicht auf Anhieb ansieht. Deswegen ist es gut, 
sich beizeiten einige Vorsichtsmaßnahmen anzueignen, wenn man Macros 
schreibt.

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.