Forum: Compiler & IDEs Arbeiten mit C und H Dateien


von Huber M. (michael_h784)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche hier aus meinem Buch. Die Aufgabe.... Arbeiten mit C und H 
dateien... nach zu vollziehen. Jetzt habe ich aber ein Problem, und 
zwar, wenn ich das ganze compiliere kommt gleich ein Fehler (bild1)
1
Error  1  main.h: No such file or directory  C:\Users\Daniela Weinhart\Documents\Atmel Studio\Arbeiten mit C und H dateien\Arbeiten mit C und H dateien\Arbeiten mit C und H dateien.c  9  18  Arbeiten mit C und H dateien

und ich komme nicht darauf was ich da falsch mache. Ich habe die ganzen 
C und H dateien Erstellt und abgespeichert. Und dann wie im (bild1) zu 
sehen rechts im soloution expolorer geAdded.

im (bild2) habe ich die main.h datei mal wie ich sie geschreieben 
habe..Das müsste doch alles so stimmen ? könnte mir bitte jemand 
weiterhelfen?


grüsse huber

von Bernd K. (prof7bit)


Lesenswert?

Die Datei scheint nicht "main.h" sondern "Datei main.h" zu heißen.

Vielleicht fängst Du erstmal damit an die ganzen Ordnernamen und 
Dateinamen in den Griff zu bekommen, und wenn Du schon dabei bist dann 
ist es auch nützlich gleich mal dafür zu sorgen daß die Ordner-Namen und 
Dateinamen kürzer werden und vor allen Dingen auch keine Leerzeichen 
drin vorkommen, die Leerzeichen sind im besten Falle zu nichts nütze und 
im schlechtesten Falle führen sie zu Fehlern in Tools die damit nicht 
zurechtkommen.

: Bearbeitet durch User
von Huber M. (michael_h784)


Angehängte Dateien:

Lesenswert?

Danke das war ein wertvoller Tipp. Somit hat sich das problem gleich 
erledigt.

Jetzt kommt aber gleich noch ein problem(bild3), warum meckert er jetzt 
bei den variablen uint8_t c = 10; zb. die habe ich ja auch noch mit 
extern uint_t c;
deklariert, damit er sie überall erkennt. es scheint wohl alles mit 
uint8_t nicht mehr zu stimmen

von Timmo H. (masterfx)


Lesenswert?

Steht da doch "unknown type..." du musst noch die stdint.h includen um 
die typen zu benutzen

von Huber M. (michael_h784)


Lesenswert?

Timmo H. schrieb:
> Steht da doch "unknown type..." du musst noch die stdint.h includen um
> die typen zu benutzen

Ja das steht da. habe es probiert mit der stdint.h das ändert nichts. 
Und die funktionieren ja sonst auch immer, auch ohne dieser stdint.h 
datei.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Huber M. schrieb:
> habe es probiert mit der stdint.h das ändert nichts.

Dann hast Du es nicht richtig probiert.

von Huber M. (michael_h784)


Lesenswert?

Rufus Τ. F. schrieb:
> Dann hast Du es nicht richtig probiert.

also einmal so
1
#include "stdint.h"
und einmal so
1
#include <stdint.h>
und anschliessend jeweils neu compiliert

: Bearbeitet durch User
von Timmo H. (masterfx)


Lesenswert?

Huber M. schrieb:
> und einmal so #include <stdint.h>
so ist es richtig

Und in welchen Quell-File hast du es included? vermutlich nur in er 
main.c. Das hilft aber z.B. noch lange nicht der mult.c und auch nicht 
der mult.h, sofern du es nicht direkt vor dem include der mult.h gemacht 
hast.

: Bearbeitet durch User
von Huber M. (michael_h784)


Lesenswert?

Ok das ist logisch, jetzt kommt kein fehler mehr, puh das kam jetzt die 
letzten 0 - 100 seiten nicht vor mit der stdint.h . ich habe sie jetzt 
in jeder C und H datei ganz oben eingebunden. Dann hat mir jetzt zweimal 
der Präprozessor gemeckert ?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Huber M. schrieb:
> ich habe sie jetzt in jeder C und H datei ganz oben eingebunden.

In die .h-Dateien musst Du sie nicht einbinden, wenn Du dafür sorgst, 
daß Du in allen C-Dateien vorher die stdint.h einbindest.

Wenn Du sie aber in die .h-Dateien einbindest, brauchst Du sie in die 
.c-Dateien nicht mehr einzubinden. Das wäre redundant.

Und ja: Lerne den Unterschied in der Bedeutung zwischen

#include "xxx"

und

#include <xxx>

von Rolf M. (rmagnus)


Lesenswert?

Rufus Τ. F. schrieb:
> Huber M. schrieb:
>> ich habe sie jetzt in jeder C und H datei ganz oben eingebunden.
>
> In die .h-Dateien musst Du sie nicht einbinden, wenn Du dafür sorgst,
> daß Du in allen C-Dateien vorher die stdint.h einbindest.

Abhängigkeiten von Include-Reihenfolgen sind zu vermeiden. Am 
sinnvollsten ist es daher, sie in allem einzubinden, in dem der Typ 
benutzt wird.  Wobei ein .c-File sein dazugehöriges .h-File sowieso 
sinnvollerweise immer inkludiert, also braucht man es in dem Fall nur in 
einem der beiden Files zu tun.

von Bernd K. (prof7bit)


Lesenswert?

Rufus Τ. F. schrieb:
> In die .h-Dateien musst Du sie nicht einbinden, wenn Du dafür sorgst,
> daß Du in allen C-Dateien vorher die stdint.h einbindest.

Das wäre schlechter Stil. Jeder Header sollte all das selbst 
inkludieren was er benötigt, ein Header soll nicht voraussetzen daß er 
nur in irgendeinem bestimmten Kontext inkludiert werden darf, er muss 
vollkommen autark funktionieren.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Bernd K. schrieb:
> Das wäre schlechter Stil.

Das ist eine Stilfrage. Es gibt die "jeder includiert 
alles"-Philosophie, und es gibt das Gegenteil.

Letzteres hilft möglicherweise etwas besser beim Erkennen von 
Abhängigkeiten.

von Nop (Gast)


Lesenswert?

Rufus Τ. F. schrieb:

> Das ist eine Stilfrage. Es gibt die "jeder includiert
> alles"-Philosophie

Im Realleben fängt man sich damit aber auch schon Krankheiten aller Art 
ein. ;-)

von Bernd K. (prof7bit)


Lesenswert?

Rufus Τ. F. schrieb:
> Das ist eine Stilfrage. Es gibt die "jeder includiert
> alles"-Philosophie, und es gibt das Gegenteil.

Nein, die mein ich nicht, das ist Chaos pur. Ich meine die "Jeder Header 
includiert genau das war er braucht, nicht mehr und nicht weniger 
Philosophie", damit geht einher daß es nun keine Rolle mehr spielt in 
welcher Reihenfolge man die Header includiert und daß jeder header für 
sich vollkommen autark betrachtet und verwendet werden kann weil er oben 
alle seine Abhängigkeiten explizit erklärt.

Beispiel: Du verwendest Posix-Typen in Deinem Header? Dann includiert 
der header stdint.h. Er verlässt sich nicht drauf daß das irgendwo 
anders geschehen muss oder daß eine bestimmte Reihenfolge eingehalten 
werden muss, denn die Abhängigkeiten "sortieren" sich bei dieser Methode 
wie von Zauberhand selbst über die include guards.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wir reden wohl aneinander vorbei. Du hast Dich auf eine Formulierung 
von mir festgebissen, die ich als Option erwähnte.

Es ist natürlich sinnvoll, die "jeder Header includiert, was er 
braucht"-Philosophie anzuwenden, aber um sie anwenden zu können, muss 
der Benutzer erst mal verstehen, was er da macht - wie z.B. er 
herausfinden kann, welche Header er denn wirklich für seine Headerdatei 
braucht.

Ohne diese Fähigkeit, ohne dieses Verständnis wird wild alles, was 
irgendwo nach *.h aussieht, irgendwo reingeklatscht. Und hier gibt es 
oft noch viel elementarere Verständnisprobleme - im Sprachgebrauch viel 
zu vieler Nutzer hier etabliert sich "lib" oder "library" als Synonym 
für Headerdatei, was natürlich kompletter Blödsinn ist und bei der 
Hilfesuche jedesmal zu Konfusion führt.

Und um eine Arbeitsphilosophie anzuwenden, ist es sinnvoll, sie zu 
verstehen. Und das Verstehen entwickelt sich nicht aus dem 
luftleeren Raum heraus, oder weil das in "nem Tut" drinstand, sondern 
weil man das durch Ausprobieren und Betrachten der Resultate 
nachvollziehen konnte.

Ansonsten, wenn man mit einem Compiler arbeitet, der das Konzept der 
"präcompilierten Headerdateien" kennt, dann ist dafür die Einhaltung der 
Include-Reihenfolge wichtig. Funktional ist sie bei sauberer Gestaltung 
der Dateien mit entsprechenden Include-Guards nicht nötig, aber die 
"präcompilierten Header" fallen dann als Mittel zur Beschleunigung des 
Übersetzungsvorganges aus.

(Allerdings: Das ist kein Anfängerthema, wer begreifen will, wie 
Headerdateien arbeiten, sollte von so einem Werkzeug die Finger lassen - 
bei den Projektgrößen, mit denen da gearbeitet wird, ist das auch 
komplett überflüssig)

von Huber M. (michael_h784)


Angehängte Dateien:

Lesenswert?

Hallo,

mal wieder, also ich komme immer noch nicht klar mit den includen von h 
und c Dateien. Bzw. das Grundprinzip ist mir schon einigermassen klar, 
aber wie die hier im Anhang, die ich allerdings bekommen habe. Versuche 
ich verzweifelt zu Verknüpfen. Denn hier kannte er die Bool Variablen 
nicht die ich mit #include stdbool allerdings behoben habe, aber jetzt 
erkennt er mir die Byte variablen nicht.

ich benutze das Atmel Studio 6.2 könnte mir vielleicht anhand des 
Anhangs mal zeigen wie mann das richtig macht. Ich würde am liebsten 
alle includes bei den includeguards nochmal raus Löschen und neu machen.

grüsse Huber

von Dirk B. (dirkb2)


Lesenswert?

In jeder Datei (.c oder .h) in der du bool benutzt, muss das bool auch 
bekannt sein
I.A. reicht da ein #include <stdbool> in der Datei aus.

byte ist keine Definition vom Standard. Die musst du also selber 
definieren.

Das kann ein signed char oder unsigned char sein, je nachdem ob es ein 
Vorzeichen hat.
Evtl sind int8_t bzw. uint8_t aus <stdint> besser.


Wenn du in tea56xx.c Funktionen aus i2c.c benutzt, die in i2c.h 
deklariert sind, dann musst du in tea56xx.c  auch i2c.h ber include 
einbinden.

Und ein extern ist bei der Deklaration von Funktionen nicht nötig.

: Bearbeitet durch User
von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

Huber M. schrieb:
> mal wieder, also ich komme immer noch nicht klar mit den includen von h
> und c Dateien. Bzw. das Grundprinzip ist mir schon einigermassen klar,
> aber wie die hier im Anhang, die ich allerdings bekommen habe.

O je. Ich hatte wirklich nicht vermutet, daß du bereits mit den 
Fundamenten des Ganzen derartige Probleme hast. Zunächst mal zieh dir 
die StdTypes.h aus dem Anhang  und guck sie dir an.

Das ist meine Typologie, die ich konsequent benutze, weil ich auch noch 
anderes als bloß C-Programmieren zu tun habe. Guck ruhig auch mal in 
deine "stdint.h" die sich irgendwo in deinen Compiler-Verzeichnissen 
befindet. Dort wirst du sehen, daß dort der uint8_t auch bloß auf's 
unsigned char heruntergebrochen wird, bevor der Compiler ihn zu fressen 
kriegt. (ob das nun per #define oder per typedef passiert, ändert am 
finalen unsigned char nix.)

Andere Leute mögen jetzt aufkreischen und schreiben, daß man doch 
unbedingt ein uint8_t für's byte nehmen sollte, aber das ist mir zu 
doof, schließlich fragst du deinen PC-Händler ja auch nicht, wieviel 
Giga-uint8_t's der an RAM drinne hat. Vermutlich würde sich der Handler 
an den Kopf fassen und dich ganz vorsichtig aus dem Laden befördern...

So und nun zum Verhältnis .c und .h etwas:
C-Quellen heißen für gewöhnlich "irgendwas.c". Aber normalerweise 
klatscht man ja nicht alles und jedes in eine riesige "elefant.c", 
sondern trennt die verschiedenen Programmteile in einzelne Quellen auf. 
Nach welchen Gesichtspunkten ist erstmal egal, da gibt es 
untershiedliche Geschmäcker.

Nun will man ja dann auch in einer Quelle mal auf Funktionen und 
Variablen zugreifen, die in einer anderen Quelle stehen. Genau DAFÜR 
sind die .h Dateien da. Man schreibt in so eine .h sogenannte 
Prototypen, was hochtrabend klingt, aber ganz einfach ist: es ist eben 
genau das, was man aus der betreffenden C-Quelle für andere Quellen 
zugänglich machen will.

Steht nun in deiner Quelle ottokar.c etwa sowas:
int Egon;
void Joerg(int Hausnummer)
{......}

dann setzt man in die Headerdatei ottokar.h das Folgende hinein:
extern int Egon;
extern void Joerg(int Hausnummer);

und bindet diese Datei in alle anderen Quellen ein, die diesen Krempel 
benötigen. Also z.B. in der Quelle karlheinz.c etwa so:

#include "ottokar.h"

und schon kann man in karlheinz.c die Funktion Joerg aufrufen. Merke, 
daß mit #include schlichtweg der Inhalt der angegebenen Datei eingefügt 
wird. Merke auch, daß bei "ottokar.h" der Compiler im Verzeichnis der .c 
nach der Datei sucht, während er bei <ottokar.h> im Verzeichnis des 
Compilers für die standardmäßigen Headerdateien suchen würde.
Ach ja: Auch in ottokar.c bindet man den selben Header ein, also so:

#include "ottokar.h"
int Egon;
void Joerg(int Hausnummer)
{......}

Der Zweck ist, daß es der Compiler merken kann, wenn sich zwischen der 
.c und der .h eine Ungereimtheit eingeschlichen haben sollte.

Soweit klaro?

Du hattest in meinen Quellen erstmal die StdTypes.h rausgeschmissen, 
weswegen der Compiler die Typen bool und byte nicht kennt und dich 
angepfiffen hat. Ist logisch, gelle?


W.S.

von Markus F. (mfro)


Lesenswert?

W.S. schrieb:
> Zunächst mal zieh dir
> die StdTypes.h aus dem Anhang  und guck sie dir an.

warum erfindest Du einen (zweitklassigen) Ersatz für die Standard-Header 
stdint.h und stdbool.h?

von Rolf M. (rmagnus)


Lesenswert?

Markus F. schrieb:
> W.S. schrieb:
>> Zunächst mal zieh dir
>> die StdTypes.h aus dem Anhang  und guck sie dir an.
>
> warum erfindest Du einen (zweitklassigen) Ersatz für die Standard-Header
> stdint.h und stdbool.h?

Um ehrlich zu sein, finde ich den nicht nur zweitklassig. Ich würde 
praktisch alles darin anders machen, als es dort gemacht ist - wenn der 
Header nicht eh schon komplett überflüssig wäre. Das einzige, was C 
nicht schon in besserer Form mitliefert, sind der T-Punkt und das 
T-Rechteck - was auch immer die jetzt zu so grundlegenden Dingen macht, 
dass sie auch in diesem Header stehen müssen.

von S. R. (svenska)


Lesenswert?

Die Definition von "TRUE" als "1" ist zudem grob fahrlässig.

Dieser Header ist als wunderbares Negativbeispiel zu gebrauchen und 
sollte nach Möglichkeit nirgends verwendet werden.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Andere Leute mögen jetzt aufkreischen und schreiben, daß man doch
> unbedingt ein uint8_t für's byte nehmen sollte, aber das ist mir zu
> doof,

Du siehst und argumentierst hier viel zu kurzsichtig. Intention der 
stdint.h ist es, eine verlässliche Typenbreite für 8, 16, 32 und 64 Bit 
zu bekommen. Für 8 Bit magst Du mit "unsigned char" in 99,9% aller Fälle 
recht haben, aber das hier aus Deiner StdTypes.h:
1
#define  integer   short int
2
#define  word      unsigned short int
3
#define  byte      unsigned char
4
#define  dword     unsigned long
5
#define  qword     unsigned long long
6
#define  int64     long long

ist höchst unportabel. Je nach Prozessor bekommst Du verschiedene 
Typenbreiten heraus. Deine StdTypes.h verdient ihren Namen nicht.

Beispiel:
1
#include <stdio.h>
2
3
#define dword   unsigned long
4
5
int main ()
6
{
7
    printf ("%ld\n", sizeof (dword));
8
    return 0;
9
}

Ergebnis auf 32-Bit-Linux:
1
$ cc a.c && ./a.out
2
4

Ergebnis auf 64-Bit-Linux:
1
$ cc a.c && ./a.out
2
8

Sinn und Zweck der echten stdint.h ist es, immer die richtige Typbreite 
zu erhalten - unabhängig von der Zielplattform. Das kann Dein "Ersatz" 
überhaupt nicht leisten.

Frage: Warum nimmst Du von Deinem Auto die passenden Reifen (stdint.h) 
ab und montierst Holzräder (StdTypes.h)? Und warum machst Du auch noch 
vehement Werbung für die Holzräder?

EDIT:
Wenn Du tatsächlich mit "byte", "word", "dword" usw. arbeiten willst, 
weil Dir die Typen uint8_t, uint16_t usw. zu "doof" erscheinen, dann 
schreibe doch in Deine StdTypes.h:
1
#include <stdint.h>
2
#define  integer   int16_t
3
#define  word      uint16_t
4
#define  byte      uint8_t
5
#define  dword     uint32_t
6
#define  qword     uint64_t
7
#define  int64     int64_t

Damit wird auch Deine StdTypes.h portabel und Du musst die "doofen" 
Typen nicht weiter im Quelltext benutzen.

Sehr interessant ist übrigens Dein Kommentar:
1
/* rausgenommen wegen Chan's FF
2
...
3
*/

Das lässt erkennen, dass Du mit Deinen selbstgefrickelten Typen bereits 
mit Chans selbstgefrickelten Typen in einen Konflikt gelaufen bist. Mit 
stdint.h wäre das nicht passiert.

: Bearbeitet durch Moderator
von Tom (Gast)


Lesenswert?

Rolf M. schrieb:
> Ich würde
> praktisch alles darin anders machen

Ein echter W.S. halt. Wie immer gilt: Wenn man von allem das Gegenteil 
tut, ist man zu 99.7% auf dem richtigen Weg.

von Markus F. (mfro)


Lesenswert?

Frank M. schrieb:
> Sinn und Zweck der echten stdint.h ist es, immer die richtige Typbreite
> zu erhalten - unabhängig von der Zielplattform. Das kann Dein "Ersatz"
> überhaupt nicht leisten.

Das ist nicht der Punkt. Wenn man sich genügend bemüht, kann man auch 
adäquaten Ersatz schreiben.

Der Punkt ist: wenn man (der Hase) auf einer neuen Plattform ankommt, 
ist stdint.h (der Igel) immer schon da. Man kann nur verlieren.

von W.S. (Gast)


Lesenswert?

Markus F. schrieb:
> warum erfindest Du einen (zweitklassigen) Ersatz für die Standard-Header
> stdint.h und stdbool.h?

Feuerzangenbowle: Weil ich zuerst dagewesen bin.

Mal im Ernst: Ich programmiere nun schon einige Jahrzehnte und meine 
Standard-Typen, die ich eben auch in C verwende, sind älter als stdint 
und sie sind umfassender. Ich sollte also eher die Frage stellen, warum 
die C-Leute auf so einen Kruscht kommen anstatt sich an das zu halten, 
was bereits seit langem üblich ist.

W.S.

von W.S. (Gast)


Lesenswert?

Frank M. schrieb:
> Du siehst und argumentierst hier viel zu kurzsichtig. Intention der
> stdint.h ist es, eine verlässliche Typenbreite für 8, 16, 32 und 64 Bit
> zu bekommen.

Hör zu, mein Lieber, höre mir mal GENAU zu!

Eine verläßliche Datenbreite hätte man als Normungsgremium allein 
dadurch festlegen können, daß man eben die Grund-Datentypen int, long 
usw. endlich mal wirklich für alle Compiler echt festlegt. Ist aber 
nicht geschehen. Die Intention sehe ich sehr wohl, aber es ist ein für 
die µC-Szene völlig unnützer Rohrkrepierer draus geworden.

Stattdessen hat man vor den C-Betonköpfen kapituliert, hat die 
wabbeligen Festlegungen für die Compiler eben NICHT auf präzise 
Bitgrößen festgenagelt und die Kapitulationsurkunde in Form einer 
Header-Datei unterschrieben, die in keiner Weise ein Teil der 
eigentlichen Toolchain ist, sondern eben nur ein Beiwerk, das 
prinzipiell ein jeder sich nach seinem Gusto editieren könnte - so er 
wollte.

Die bekannten "U8", "U16" und so weiter sind da nichts anderes und von 
Dingen wie Endianness können wir mal ganz absehen, da ist der Horizont 
derer, die hier sich wild aufführen, einfach zu klein. Ich habe genug 
Motorola, Fujitsu, NEC und ARM zu gleicher Zeit unter den Fingern 
gehabt, um zu wissen, was ich mit den diversen Integertypen tue oder 
lieber bleiben lasse. Da ist auch eine <stdint.h> nicht wirklich 
hilfreich.

Kurzum, es ist da bei C99 ein Haufen heißer Luft entstanden, der 
lediglich zu unleserlichen Bezeichnungen geführt hat, aber das 
Kernproblem überhaupt nicht tangiert. Schaumschlägerei.

Also laß diese unnütze Diskussion. Ich habe aus gutem Grunde dies 
bereits weiter oben dediziert geschrieben.

Meinen Code wird garantiert niemand auf einem 64 Bit Linux einsetzen 
wollen und ein Stück Code, was für einen µC geschrieben wurde, hat auch 
niemals den Anspruch, in einer dafür völlig ungeeigneten Umgebung 
eingesetzt zu werden - also ist diese Argumentation überflüssig.

Nochmal im Klartext: Wir reden hier in diesem Forum nicht über 64 Bit 
Linux, sondern über Mikrocontroller - und zwar solche von der eher 
kleineren Sorte, also keine aus der Riege a la 64Bit-Cortexe oder 
64Bit-MIPSe.

Dieses Abschweifen ist in diesem Thread ohnehin völlig überflüssig, denn 
hier geht es um was ganz anderes. Also!!

Und nun solltet ihr euch lieber den Nöten des TO zuwenden, das wäre 
insgesamt hilfreicher. Immerhin will er sein Radio in Gang kriegen - und 
das hängt nicht von der Verwendung von <stdint.h> ab, sondern von ganz 
anderen Verständnisproblemen, wie z.B. dem Verständnis von .h Dateien.

W.S.

Nochwas:
Frank M. schrieb:
> Das lässt erkennen, dass Du mit Deinen selbstgefrickelten Typen bereits
> mit Chans selbstgefrickelten Typen in einen Konflikt gelaufen bist. Mit
> stdint.h wäre das nicht passiert.

Das hast du grandios MISSVERSTANDEN.
Diese Datentypen sind bei mir in exakt gleicher Weise wie bei Chan 
deklariert, aber da ich dessen exakt gleichlautende #defines nicht aus 
seinen Quellen herauslöschen wollte, habe ich sie bei mir 
auskommentiert. Du wirst - hoffentlich - verstehen, was passiert, wenn 
man zwei gleichlautende #define's für denselben Datentyp im Code hat. 
Klaro jetzt?

von S. R. (svenska)


Lesenswert?

W.S. schrieb:
> Feuerzangenbowle: Weil ich zuerst dagewesen bin.

Dann wäre langsam der Zeitpunkt gekommen, deine StdTypes.h auf die 
moderneren Typen umzustricken. Alternativ kannst du auch deinen Code auf 
Typnamen umstricken, die nicht schon seit Windows 95 inhaltlich falsch 
sind.

Wenn du das nicht willst, dann bitte veröffentliche das nie wieder.

W.S. schrieb:
> Du wirst - hoffentlich - verstehen, was passiert, wenn
> man zwei gleichlautende #define's für denselben Datentyp im Code hat.

Wenn sie exakt gleich sind, akzeptiert gcc das.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

W.S. schrieb:
> Feuerzangenbowle: Weil ich zuerst dagewesen bin.
>
> Mal im Ernst: Ich programmiere nun schon einige Jahrzehnte und meine
> Standard-Typen, die ich eben auch in C verwende, sind älter als stdint
> und sie sind umfassender. Ich sollte also eher die Frage stellen, warum
> die C-Leute auf so einen Kruscht kommen anstatt sich an das zu halten,
> was bereits seit langem üblich ist.

Vielleicht einfach deswegen, weil "die C-Leute" im 
Standardisierungsgremium sitzen und Du nicht?

Wenn Du unbedingt deine eigenen Typen haben willst, spricht ja überhaupt 
nichts dagegen, die auf Grundlage der stdint.h neu zu definieren anstatt 
den alten Schrott weiter mit sich rumzuschleppen (und ihn auch noch in 
Foren als den Stein der Weisen zu verkaufen).

Man kann immer auf C schimpfen (was Du ja regelmäßig und anscheinend mit 
Genuß tust), aber dann sollte man nach meiner Meinung vernünftige 
Verbesserungen im Standard auch annehmen, wenn sie denn mal kommen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Meinen Code wird garantiert niemand auf einem 64 Bit Linux einsetzen
> wollen

Das mit dem 64-Bit-Linux war lediglich ein Beispiel. Du meinst also, 
dass bei 32 Bit bei den µCs bereits Schluss ist? Da sollte man durchaus 
weitsichtiger sein.

Was gefällt Dir denn nicht an uint16_t? Da weiß ich auf den ersten 
Blick, dass es sich um 16 Bit handelt. Bei "word" oder "dword" muss ich 
zweimal nachdenken. Und witzigerweise schreibst Du dann in Deiner 
StdTypes.h selbst "int64". Sollte das nicht konsequenter dann "qword" 
heißen? Oder besser noch "sqword" - für "signed quad word". Aber Moment, 
da muss man erstmal rechnen:

  sqword = signed quad word = 4 x 2 Bytes = 8 Bytes

Uff, da kann man schon mal beim Lesen eines Quellcodes ins Schwitzen 
kommen. Gut, dass Du auf "qword" verzichtet hast. Jedoch führst Du mit 
der Verwendung von "int64" statt "qword" bzw. "sqword" Dein eigenes 
System ad absurdum. ;-)

W.S. schrieb:
> Du wirst - hoffentlich - verstehen, was passiert, wenn
> man zwei gleichlautende #define's für denselben Datentyp im Code hat.

Gar nichts.
1
#define  dword   unsigned long
2
#define  dword   unsigned long
3
#define  dword   unsigned long
4
#define  dword   unsigned long
5
#define  dword   unsigned long
6
#define  dword   unsigned long
7
8
int main ()
9
{
10
    printf ("%u\n", sizeof (dword));
11
    return 0;
12
}
1
$ cc -Wall -Wextra a.c && ./a.out
2
8

Kein Fehler, keine Warnung.

> Klaro jetzt?

Ich verstehe Deine Betonkopfhaltung durchaus. Ich selbst programmiere in 
C seit 1984, habe auch ziemlich viele C-Compiler erlebt - gute wie 
schlechte. Trotzdem sollte man bestimmte Innovationen auch als älterer 
Mensch durchaus  akzeptieren. Ja, ich bin auch ein alter Knochen, aber 
stdint.h ist gerade für die µC-Programmierung ein gewaltiger 
Fortschritt, den man nicht ablehnen sollte. Da kann man durchaus auch 
mal selbstgefrickelte Datentypen über Bord werfen. Den Schritt habe ich 
bereits vor Jahren gemacht. Und darüber bin ich froh.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Eine verläßliche Datenbreite hätte man als Normungsgremium allein
> dadurch festlegen können, daß man eben die Grund-Datentypen int, long
> usw. endlich mal wirklich für alle Compiler echt festlegt.

Nein, das wäre fatal gewesen. Dennis Ritchie war damals bereits in den 
70er Jahren sehr weitsichtig, als er den Datentyp "int" als die 
natürliche Datenbreite des verwendeten Prozessors definierte und sich 
NICHT auf eine feste Datenbreite festlegte.

Sonst hätten nämlich im Laufe der Zeit sämtliche C-Programme und 
C-Bibliotheken, die jemals entwickelt wurden, immer wieder umgeschrieben 
werden müssen, um die Datentypen an die Entwicklung der Hardware 
anzupassen. Das wäre ein nicht vertretbarer Aufwand gewesen. Als damals 
die PDP11, auf der Unix (und damit auch C) entwickelt wurde, durch 
32-Bit-Maschinen abgelöst wurden, musste der Typ "int" einfach an die 
Datenbreite des Prozessors angepasst werden und schon liefen alle 
C-Programme und Bibliotheken weiter! Dasselbe geschah beim Wechsel auf 
64 Bit. Genau diese variable Definition damals vor über 40 Jahren hat C 
das Überleben gesichert.

Weitsichtig denken lohnt sich. Nichts vergeht schneller als die aktuelle 
Computertechnologie.

von W.S. (Gast)


Lesenswert?

Frank M. schrieb:
> Was gefällt Dir denn nicht an uint16_t? Da weiß ich auf den ersten
> Blick, dass es sich um 16 Bit handelt. Bei "word" oder "dword" muss ich
> zweimal nachdenken. Und witzigerweise schreibst Du dann in Deiner
> StdTypes.h selbst "int64". Sollte das nicht konsequenter dann "qword"
> heißen? Oder besser noch "sqword" - für "signed quad word". Aber Moment,
> da muss man erstmal rechnen:

Nö, da brauchst du nix zu rechnen.
Ich bin am PC hauptsächlich mit Pascal in diversen Schattierungen 
unterwegs und dort sind für vorzeichenlose Int's eben byte, word, dword, 
qword die Mode (auch smallword, wenn man es dedizierter festlegen will) 
und für vorzeichehaltiges hat es integer, longint und int64.

Das sind dem Compiler eingebaute Typen, sie bedürfen also keinerlei 
Benennerei durch einen selbst, wie das hier bei C mit Headerdateien 
gemacht wird, die derartige Zweitbenennungen a la typedef beinhalten.

Ich bin es gewohnt, mit ganz anderen Dingen umzugehen, z.B, daß ein char 
durchaus nicht immer 8 Bit umfaßt, sondern heutzutage eben 16 Bit und 
daß man be Bedarf an einem 8 Bit char eben einen ansichar nehmen muß. 
Ebenso, daß man eben nicht char's mit integertypen 
durcheinanderpurzeln lassen kann.

Und dieses intxy_t Getue trifft auch nicht die echten Probleme. Mir 
reicht es völlig aus, daß ein simpler int mir benutzbare 16 Bit und ein 
long benutzbare 32 Bit garantiert. Das reicht. Für alles Weiter sind 
ganz andere Sachen zu bedenken: Alignment und Endianness zuvörderst. Was 
meinst du, weswegen ich die 16 Bit Offsets in meinen Fonts byteweise 
organisiert habe? Eben, weil die Fonts sich sowohl auf FR als auch auf 
ARM benutzen lassen müssen. Bei beiden würde mir das erforderliche 
Alignement auf die Füße fallen und obendrein haben FR und ARM 
unterschiedliche Endianness.

W.S.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Mir
> reicht es völlig aus, daß ein simpler int mir benutzbare 16 Bit und ein
> long benutzbare 32 Bit garantiert.

Wie ich oben

  Beitrag "Re: Arbeiten mit C und H Dateien"

in meiner zweiten Antwort darlegte, führt eine starre Festlegung der 
Basisdatentypen von int, long usw. in eine Sackgasse. Es mag sein, dass 
Dir es völlig ausreicht, weil Du viel zu kurzsichtig denkst, d.h. nur 
ein oder zwei Jährchen voraus.

Stell Dir mal vor, die C-Bibliotheksfunktion fseek() würde auch heute 
noch lediglich 32 Bit für die Positionangabe innerhalb einer Datei 
akzeptieren - wie vor 40 Jahren. Dann könntest Du heutzutage nur noch 
Filme in HD schauen, die gerade mal ein paar Minuten lang sind.

Die Nicht-Festlegung der Datenbreite von int, long usw. hat dafür 
gesorgt, dass man vor 40 Jahren bereits Programme in C erstellen konnte, 
die heute noch vernünftig laufen - auch mit Dateien, die nicht mehr 
einige KB, sondern viele GB groß sind. Die Stärke von C ist 
Portabilität. Nur diese hat dafür gesorgt, dass C bereits seit über 40 
Jahren existiert.

: Bearbeitet durch Moderator
von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Bitgrößen festgenagelt und die Kapitulationsurkunde in Form einer
> Header-Datei unterschrieben, die in keiner Weise ein Teil der
> eigentlichen Toolchain ist,

Es bleibt ein Rätsel, warum du nicht begreifen willst, dass das Unsinn 
ist. Die ist genauso Teil der Toolchain wie alle anderen 
Standard-Header. Es hätte keinen, absolut KEINEN Vorteil gehabt, diese 
Namen zu Schlüsselwörtern zu machen. Im Gegenzug dazu ist dein Header 
tatsächlich überhaupt nicht Teil der Toolchain.

> sondern eben nur ein Beiwerk, das prinzipiell ein jeder sich nach seinem
> Gusto editieren könnte - so er wollte.

Äh, ja, das könnte man wohl, so wie auch jeder den Header stdio.h oder 
math.h editieren könnte. Oder man könnte sich je nach Compiler dessen 
Quellcode runterladen und kaputt-editieren. Nur: Warum in aller Welt 
sollte man das tun wollen?
Du hast insofern recht, dass stdint.h keine Möglichkeit vorsieht, um 
Sabotage an der Toolchain zu verhindern. Das gilt aber für den Rest von 
C (und so ziemlich jeder anderen Sprache) ganz genauso.

> Kurzum, es ist da bei C99 ein Haufen heißer Luft entstanden, der
> lediglich zu unleserlichen Bezeichnungen geführt hat, aber das
> Kernproblem überhaupt nicht tangiert. Schaumschlägerei.

Was ist denn an int16_t für einen 16-Bit-Integer unleserlich? Das folgt 
einem einheitlichen Namensschema. intX_t für einen vorzeichenbehafteten 
Integer mit X Bit, uintX_t für das gleiche ohne Vorzeichen. Bei diesem 
tollen StdTypes-Header muss ich für einen vorzeichenbehafteten 
16-Bit-Integer den enorm aussagekräftigen Namen "integer" nutzen. Das 
gleiche ohne Vorzeichen heißt dann auf einmal völlig anders, nämlich 
"word", was sowieso eine schlechte Wahl ist, da dessen Bedeutung 
Prozessor-abhängig ist (Bei x86 z.B. ist damit normalweise 16 Bit 
gemeint, bei ARM dagegen 32 Bit). Einen vorzeichenbehafteten 32-Bit-Typ 
gibt es gar nicht. Bei 64 Bit heißt der Typ mit Vorzeichen int64, der 
ohne qword. Was ist denn das für ein bescheuertes Namensschema?
Über den Sinn bzw. Unsinn der Definition eines selbstgefrickelten bool 
statt eines auch richtig funktionierenden bool über stdbool.h wurde ja 
schon eingegangen.

> Meinen Code wird garantiert niemand auf einem 64 Bit Linux einsetzen
> wollen und ein Stück Code, was für einen µC geschrieben wurde, hat auch
> niemals den Anspruch, in einer dafür völlig ungeeigneten Umgebung
> eingesetzt zu werden - also ist diese Argumentation überflüssig.

Nun, ich teste derweil Algorithmen erstmal auf meinem PC mit 
64-Bit-Linux, bevor ich sie in meinen AVR-Code einbinde, weil das viel 
einfacher ist als das Programm immer erst draufzubraten und dann dort 
auszuprobieren. Wenn man es richtig macht, ist das gar nicht so schwer. 
Es gibt sicher Fallstricke, aber das ist mit etwas Erfahrung handhabbar.

Übrigens ist selbst dieser Unsinn bereits von einem Standard-Header 
abgedeckt:
1
/* Mist, den ich mir sowieso nicht merken kann */
2
#define     MOD   %
3
#define     XOR   ^
4
#define     NOT   ~
5
#define     AND   &
6
#define     OR    |

Aber vermutlich hast du da auch Angst, dass dir jemand den heimlich 
verändert.

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.