Forum: Mikrocontroller und Digitale Elektronik C Programmierung


von Sven Scholz (Gast)


Lesenswert?

Es geht darum die Werte aus einer externen Datei (data.dat) in ein Array 
einzulesen. Die Daten liegen Kommagetrennt vor.
Bin auf folgende Codezeile gestoßen:

int dm data_tx[100] = { #include "data.dat" };

Geht das damit tatsächlich? Ich habe früher immer eine richtige 
Dateiarbeit mit Schleifen aufgesetzt...

Kann ich das damit also machen? Sind euch irgendwelche Vor-/Nachteile 
bekannt???

DANKE.

von schnudl (Gast)


Lesenswert?

Du missbrauchst hier den C-Präprozessor um den Inhalt des angegebenen 
Files an die Stelle des Includes zu schreiben. Solange das File so 
gebaut ist, dass es in den Kontext der Array Initialisierung passt wird 
das wohl gehen.

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


Lesenswert?

Sven Scholz wrote:

> int dm data_tx[100] = { #include "data.dat" };
>
> Geht das damit tatsächlich?

Laut C-Standard so nicht, aber so:
1
int dm data_tx[100] = {
2
#include "data.dat"
3
};

Das # muss das erste (nichtleere) Zeichen in der Zeile sein.

von Niels H. (monarch35)


Lesenswert?

Wo hastn das her?

Soweit ich das weiss, geht das mit einem Standardkonformen kompiler 
bestimmt nicht.. Das '#'-Zeichen, das ein Prefix für eine 
Precompiler-Anweisung verwendet wird, muss immer am Zeilenanfang stehen. 
Hinzukommt, daß eine include-Datei nicht an der Stelle in den Quellcode 
eingefügt wird, sondern sie wird in der Regel für sich alleine geparst.

von Niels H. (monarch35)


Lesenswert?

Jörg Wunsch wrote:

> Laut C-Standard so nicht, aber so: [...]


gut, dann bin ich falsch informiert ;)

von Johannes M. (johnny-m)


Lesenswert?

Niels Hüsken wrote:
> Hinzukommt, daß eine include-Datei nicht an der Stelle in den Quellcode
> eingefügt wird, sondern sie wird in der Regel für sich alleine geparst.
Nö. Gerade eine #includierte Datei wird natürlich nicht separat 
geparst. Andernfalls könnte man keine Deklarationen in Headerdateien 
machen...

Ich denke Du verwechselst da was: Dateien, die nicht mit #include 
eingebunden werden, werden separat bearbeitet, was der Grund für die 
Verwendung von Header-Dateien mit Prototypen- und "extern"-Deklarationen 
ist (die dann wiederum mit #include eingebunden werden, damit der 
Compiler beim Parsen der betreffenden Datei die Variablen und Funktionen 
kennt).

Eine mit #include eingebundene Datei wird (vom Präprozessor) 1:1 an der 
Stelle der #include-Anweisung eingefügt.

von Bernhard M. (boregard)


Lesenswert?

Die include-Datei wird seperat nur vom Präprozessor geparsed, aus Sicht 
des C-Compilers gibt es nur eine einzige Datei, in die schon alle 
includes eingefügt sind.
Von daher geht das "richtige" Beispiel von Jörg Wunsch und ist nicht 
unüblich, wenn Daten in ein Programm hineinkompiliert werden sollen / 
müssen.

von Jojo S. (Gast)


Lesenswert?

>Geht das damit tatsächlich? Ich habe früher immer eine richtige
>Dateiarbeit mit Schleifen aufgesetzt...

der Unterschied ist hoffentlich klar: so wird der Dateiinhalt zur 
Laufzeit gelesen, beim #include wird die Variable zur Kompilierzeit 
festgelegt. Für Daten die sich nicht mehr ändern ist includieren schon 
praktisch, z.B. für Zeichenfonts für Displays die man mit dann mit einem 
externen Tool erzeugen kann.

von Severino R. (severino)


Lesenswert?

Sven Scholz wrote:
> Es geht darum die Werte aus einer externen Datei (data.dat) in ein Array
> einzulesen. Die Daten liegen Kommagetrennt vor.

Soll das Einlesen denn zum Zeitpunkt des Kompilierens oder später zur 
Laufzeit geschehen?

von Simon K. (simon) Benutzerseite


Lesenswert?

Bernhard M. wrote:
> Die include-Datei wird seperat nur vom Präprozessor geparsed, aus Sicht
> des C-Compilers gibt es nur eine einzige Datei, in die schon alle
> includes eingefügt sind.

Die Datei wird soweit ich weiß nicht einzeln geparsed. Bei einem 
#include wird sämtlicher Text der inkludierten Datei 'reingeholt und 
anschließend wird weitergeparsed (nicht nach den inkludierten Daten, 
sondern am Anfang der inkludierten Daten)

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


Lesenswert?

Simon K. wrote:

>> Die include-Datei wird seperat nur vom Präprozessor geparsed, ...

> Die Datei wird soweit ich weiß nicht einzeln geparsed.

Nein, obige Aussage ist schon korrekt: die include-Datei wird vom
Präprozessor separat geparsed.  Der Präprozessor arbeitet dabei
(anders als der C-Compiler selbst) simpel zeilenweise alles durch.
Sein Parser ist aber sehr einfach, da er nur die Präprozessoranweisungen
selbst (mit # beginnend) und gültige C-Namen erkennen muss.  Letztere
sind potenzielle Kandidaten für eine mögliche Makro-Ersetzung, daher
muss der Präprozessor sie bereits parsen.

von I_ H. (i_h)


Lesenswert?

Das ist nichtmal auf C Identifikatoren festgelegt, der GNU Assembler 
benutzt auch den (C-)Präprozessor.

Die Sache mit dem #include ist aber gerade eine der schönen Seiten von 
C/C++. Man muss nicht wissen wierum der Compiler irgendwelche Dateien 
liest oder was er als erstes parst, das gibt man als Programmierer 
einfach im Code vor und genauso und nicht anders wird es gemacht - 
eingebundene Dateien erscheinen da wo's #include steht.

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


Lesenswert?

I_ H. wrote:

> Das ist nichtmal auf C Identifikatoren festgelegt, der GNU Assembler
> benutzt auch den (C-)Präprozessor.

Nein. ;-)

Wenn, dann macht das der Compiler, indem du ihm eine .S-Datei
übergibst.  Er ruft dann den Präprozessor auf und mit dem Ergebnis
den Assembler.

Trotzdem bleibt die Ersetzung der Makros auf C-Bezeichner beschränkt.
Wenn also der Assembler eine andere Syntax für Bezeichner benutzen
würde (beispielsweise Namen gestatten, die einen Punkt beinhalten),
dann könnte man diese nicht durch Makros ersetzen lassen.

Da der Präprozessor aber eben den Rest nicht parsed, kann das ein
ansonsten beliebiger Text sein.  (C-Kommentare ersetzt er übrigens
noch durch Leerzeichen.)

von I_ H. (i_h)


Lesenswert?

GAS benutzt es soweit ich weis auch. Klar, eigentlich sind C Identifier 
gemeint, aber es wird halt auch an anderer Stelle benutzt. Der Rest ist 
Wortklauberei.

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


Lesenswert?

I_ H. wrote:

> GAS benutzt es soweit ich weis auch.

Nein, macht er eben nicht.  Nur, wenn du den Assembler über den
Compiler rufst.
1
% cat foo.S
2
#define FOO 42
3
mov %eax, FOO
4
% as -o foo.o foo.S
5
% nm foo.o
6
         U FOO
7
% objdump -d foo.o
8
9
foo.o:     file format elf32-i386
10
11
Disassembly of section .text:
12
13
00000000 <.text>:
14
   0:   a3 00 00 00 00          mov    %eax,0x0
15
% cc -c -o foo.o foo.S
16
% nm foo.o
17
% objdump -d foo.o
18
19
foo.o:     file format elf32-i386
20
21
Disassembly of section .text:
22
23
00000000 <.text>:
24
   0:   a3 2a 00 00 00          mov    %eax,0x2a

Gut erkennbar, dass die 42 nur im zweiten Fall ersetzt worden ist, im
ersten Fall ist das ganze #define ein Kommentar für den Assembler, und
FOO wurde nicht ersetzt sondern (stillschweigend) als "external
undefined" in die Symboltabelle aufgenommen.  Der Linker würde sich
dann später darüber erbrechen, dass er keine Definition für das
globale Symbol FOO finden kann.

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.