[C++] Mehrere Header-Dateien Fehler?

5 Antworten

Vermutlich gibt es irgendwo bereits eine Funktion "setColor"

Wenn Du C++ programmierst, solltest Du die Möglichkeiten dieser Sprache auch nutzen. Es ist z.B. guter Stil, namespaces zu verwenden (z.B. "consoleHelpers"), dann kann es keine Namenskollisionen mit Funktionen aus dem Framework geben.

Dann sollte man nur die includes einfügen, die auch verwendet werden, in tile.h ist der include überflüssig.

Weiterhin ist (m.E.) die Verwendung von Include-Guards per #define fehleranfällig, es gibt "#pragma once", das exakt dasselbe tut.

Herangehensweise:

Da dem Compiler offenbar die Funktion setColor nicht schmeckt, benennst Du die vorübergehend (z.B. in "setForegroundAndBackgroundColor" um). Es ist zumindest bemerkenswert, dass die enum nicht angemault wird.

Ich möchte meinen, es liegt an der Definition der Funktion in der Header-File (statt einer Deklaration).

Entweder du verschiebst die Funktion in eine Implementationsdatei (cpp), wo sie eigentlich auch hingehört oder du setzt einmal das Schlüsselwort inline vor die Definition:

inline void setColor(Color fg, Color bg) {
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), bg * 16 + fg);
}  

Ich denke auch, dass es daran liegt, da Funktionen ja normalerweise die externe Speicherklasse haben.

Anstatt "inline" geht ja auch "static" (was man bei C++ aber lieber durch anonyme namespaces ersetzen sollte) oder "constexpr" nutzen (im obigen Code zwar nicht, aber bei konstanten Funktionen schon).

Auf jeden Fall bin ich mir sicher, dass du mit deiner Vermutung recht hast. :)

0
@TeeTier

Vermutlich kannst du pixelinos Frage:

Aber ist es jetzt performanter ob ich es static oder inline habe?

etwas besser beantworten als ich?

0

Das dürfte (IMHO) keine Relevanz haben. <hfile> wird für Systemheader verwendet, die nichtmal als Datei vorliegen müssen, es wird dem Implementierer des Compilers überlassen.

Include mit "filename" gelten als normale Quellcode-Imports direkt in die Datei in der das include steht. Der Präprozessor ersetzt also das Inlcude mit dem Inhalt der angegebenen Datei inplace.

Stilistisch ist das natürlich trotzdem eher unschön, es dürfte aber eigentlich nicht zu einem Fehler führen.

0

Danke! Du hattest wiedermal Recht. Aber es hat mich gewundert, weil es, ohne die Tile-Klasse hat es noch funktioniert. Ich habe jetzt bei jeder Funktion in dem Header inline davor geschrieben und es funktioniert einwandfrei.

Aber ist es jetzt performanter ob ich es static oder inline habe?

Werde mich in näherer Zukunft sowieso damit beschäftigen, aber soweit bin ich noch nicht, darum frage ich jetzt einfach mal so :D

0
@pixelino

Ja, weil zu diesem Zeitpunkt die Funktion auch noch nur einmal eingebunden wurde. Bei den 2 Includes hingegen wird je Include die Funktion setColor in die jeweilige Objektdatei eingebunden. Dies wird vom Linker erst bemerkt, wenn er versucht, die erzeugten Objektdateien (Tile.o und main.o) miteinander zu verbinden. Er gerät also in einen Definitionskonflikt.

Aber ist es jetzt performanter ob ich es static oder inline habe?

Hier gilt zuerst einmal die Antwort, die dir TeeTier dazu bereits gegeben hat. Statt static sollte wenn, eher ein Namespace verwendet werden. Lies dazu hier (Abschnitt Conclusion) mehr.

Zu der Performance-Frage an sich kann ich nicht so viel sagen. Das Schlüsselwort inline suggeriert dem Compiler, dass er dort, wo die Funktion aufgerufen wird, den Code auch ruhig direkt einfügen kann (halte diese Funktionen daher möglichst klein; übrigens entscheidet der Compiler bei Funktionen die Handhabung normalerweise selbst, egal ob du inline davorsetzt oder nicht). Bei einer Lösung mit static/Namespace sollte er stattdessen alle Definitionen mit aufnehmen und sie jeweils nur lokal zur Verfügung stellen. Somit hast du bei inline vermutlich einen geringen Performance-Vorteil, aber ich denke nicht, dass dieser sonderlich erwähnenswert sein wird. Ich denke, dass es an dieser Stelle sinnvoll wäre, noch einen weiteren Kommentar einzuholen.

0

Also soweit ich sehe ist das GUARDING korrekt, zumindest sehe ich keinen augenscheinlichen Fehler.

Als stilistische Anmerkung:

Auch in eigenen Headern sollten vorzugsweise nur Deklarationen stehen.

----

Ist der Fehler denn vollständig, also exakter Wortlaut?

Welchen Compiler nutzt Du?

Vergessen, Du könntest dem Compiler noch mitteilen, daß er die Verbosity erhöht, falls möglich.

Also soweit ich sehe ist das GUARDING korrekt, zumindest sehe ich keinen augenscheinlichen Fehler.

Einen kleinen Schönheitsfehler gibt es allerdings: Bezeichner, die mit einem Unterstrich, gefolgt von einem Großbuchstaben beginnen, sind grundsätzlich als reserviert anzusehen und werden von Tools zur statischen Codeanalyse auch moniert werden.

Leider sieht man in sehr vielen Lehrbüchern und Tutorials (gefühlt die ca. Hälfte), dass Include-Guards mit Unterstrich und Großbuchstaben beginnen, was man aber laut Standard nicht tun sollte.

Grundsätzlich sind auch Bezeichner reserviert, die zwei oder mehr aufeinanderfolgende Unterstriche enthalten. Im globalen Namensraum sind außerdem Bezeichner reserviert, die mit einem Unterstrich gefolgt von einem Kleinbuchstaben beginnen (laut C++ Standard), oder auf _t enden (laut POSIX).

POSIX definiert noch viel mehr Regeln, die über den "normalen" Standard hinaus gehen, aber die würden hier den Rahmen sprengen und die oben genannten sind bei weitem die wichtigsten.

Beispiele:

Foobar // gut
_Foobar // schlecht
Foo_bar // gut
FOOBAR // gut
FOO_BAR // gut
_FOOBAR // schlecht
FOOBAR_ // gut
FOO_BAR_ // gut
FOO__BAR // schlecht
__FOO__BAR__ // schlecht
Foo__bar // schlecht
__Foobar // schlecht
Foobar_ // gut
_Foobar_ // schlecht
__Foo__bar__ // schlecht
_foobar // schlecht
foobar_ // gut
foobar__ // schlecht
foobar_t // schlecht
foobar // gut

So, das wars ... :)

PS: Das kann man alles ignorieren, wenn man in seinem stillen Kämmerlein entwickelt, aber sobald man zukunftssicheren und wartbaren Code oder eine Bibliothek schreibt, die Dritte zu Gesicht bekommen, bzw. die in fremden Projekten landet, sollte man sich unbedingt so strikt wie nur möglich an die Spezifikationen halten. :)

3
@TeeTier

Interessant, so ziemlich alle Bibliotheken nutzen _HEADERNAME_H oder gar __HEADERNAME_H - so zumindest bei Linux.

https://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html#Once-Only-Headers

Das ist was bei gcc vorgeschlagen wird, sie votieren auch auf anfängliche Unterstriche bei lokalen Headern zu verzichten, um Konflikte mit Includes der Bibliotheken zu vermeiden. Insofern wäre FILENAME_H wohl akzeptabel.

Im C-Standard habe ich auf die Schnelle nichts gefunden.

Solange es nicht zu einem Konflikt kommt, müßte das Guarding allerdings trotzdem funktionieren.

Die Frage ist (auch bei POSIX) was sind bindende Regeln und was sind Konventionen, da muß man oft sehr genau hinschauen.

2
@KarlRanseierIII

Ganz am Ende in einem Absatz hinter deinem Link schreiben die GNU-Leute zwar, dass man "_FOO" vermeiden soll, aber dass "__FOO" OK ist ... was natürlich gegen den Standard verstößt, und was die GCC-Leute eigentlich wissen müssten ... oder ich bin gerade zu müde, um einen simplen englischen Satz verstehen zu können. :)

Hier ist noch ein Link, hinter dem die Top-Antwort einige der Regeln (nicht alle!) ganz gut zusammen fasst:

https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228848

Das bezieht sich auf C++, aber für C habe ich jetzt keinen Link zur Hand, sondern nur die PDF des letzten öffentlich verfügbaren Drafts zu C11, und darin heißt es in Punkt 6.10.8.2 auf Seite 193:

None of these macro names [...] shall be the subject of a #define or a #undef preprocessing directive. Any other predefined macro names shall begin with a leading underscore followed by an uppercase letter or a second underscore.

Das bezieht sich auf vordefinierte Makros, also nicht wundern! Implizit steht dort also, dass nur vordefinierte Makros mit Unterstrich gefolgt von Großbuchstaben oder weiteren Unterstrichen definiert werden sollen ... der Absatz richtet sich an Compilerbauer.

Und in 7.1.3.1 auf Seite 200 steht ganz klar und eindeutig:

 All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.

... und weiter:

All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.

Bei POSIX-Konventionen hast du natürlich Recht, aber obige Regeln sollte man schon als bindend ansehen.

Damit wäre die Sache klar, oder? :)

1
@KarlRanseierIII

Noch ein Nachtrag zu POSIX und typedefs, die auf "_t" enden: Es ist extrem nervig, wenn zwei Bibliotheken len_t oder id_t oder ähnliche naheliegende Typen definieren.

Bibliotheken wie ALSA machen das zwar auch gewissermaßen "falsch", aber immerhin haben deren Typen lange Namen und Präfixe, sodass Dinge wie snd_seq_addr_t nicht kollidieren werden.

Ein addr_t alleine wird aber garantiert mit einer ganzen Reihe anderer Bibliotheken kollidieren ... naja, richtige namespaces sind eben ein großer Teil von C++ ... bei C muss man immer ellenlange Präfixe nutzen. ><

1
@TeeTier

Laut anderen Quellen lautet der Satz are reserved for any use by the implementation.

Sie wären also der Implementierung des Compilers vorbehalten und ihre Nutzung bettelt nach Konflikten.

Insofern stimme ich zu, man sollte es unterlassen, wie gesagt:

FILENAME_H oder auch _filename_h_ sind ja brauchbare Alternativen.

0
@TeeTier

Ich kann bei C, solange ich es nicht als Interface benötige, auch die Sichtbarkeit steuern, insofern kann ich Namen, die zur Kollission neigen könnten auf die Translation-Unit beschränken, sie tauchen dann auch nicht als globale Objektnamen auf.

Man sollte eigentlich denken, daß es Anno 2018 zum Standardrepertoire gehört, interne Utility-Functions etc. als nicht sichbar zu markieren. Aber ja, die Konfliktvermeidung ohne explizite Namespaces ist ein Riesenspaß.

0
@KarlRanseierIII

Ich habe hier noch ein Zitat zu reservierten Namen aus der gcc Dokumentation:

In addition to the names documented in this manual, reserved names include all external identifiers (global functions and variables) that begin with an underscore (‘_’) and all identifiers regardless of use that begin with either two underscores or an underscore followed by a capital letter are reserved names. This is so that the library and header files can define functions, variables, and macros for internal purposes without risk of conflict with names in user programs.

Das erklärt dann auch das Guarding in den Bibliotheksheadern.

1
@KarlRanseierIII

Ich habe es direkt aus der Primärquelle, also dem offiziellen Draft, kopiert. Kann natürlich auch sein, dass es im Standard leicht anders formuliert ist, aber ich will da jetzt kein Geld für ausgeben. :)

Und ob "_filename_h_" jetzt so OK ist, hängt davon ab, ob mit "file scope" ein "translation unit scope" oder tatsächlich nur die Datei gemeint ist.

Ich nutze in meinen Projekten immer so etwas wie ...

FIRMA_PROJEKT_MODUL_DATEI_H

... wobei ich möglichst darauf achte, nicht die für C89 definierte Bezeichnerlänge zu überschreiten. Manchmal setze ich auch noch ein "GUARD_" davor ... je nach Projektkonventionen.

Am besten einfach grundsätzlich immer alles vermeiden, was mit einem Unterstrich beginnt, bzw. mehrere davon aufeinanderfolgend enthält. Dann ist man garantiert auf der sicheren Seite ... vorausgesetzt, man nutzt sinnvolle Präfixe für Bibliotheken. :)

0
@KarlRanseierIII
Das erklärt dann auch das Guarding in den Bibliotheksheadern.

Naja, für die Compilerbauer ist das dann eben einfach nur "implementation defined", und da es ja ihre eigene Implementierung ist, auch völlig OK.

Für uns Otto-Normalbürger hingegen wäre das "undefined behavior" und sollte deshalb ein Nogo sein. :)

Aber wie du schon anfangs sagtest, macht das wirklich ein sehr großer Teil aller Entwickler falsch. Ich schätze locker 30% bis 50% aller Projekte.

Das gleiche Problem gibts ja beim Casten des zurück gegebenen void-Zeigers von malloc() ... dabei ist vielen ja auch nicht klar, wann man es tun, und wann man es möglichst vermeiden sollte. Aber naja, jede Sprache hat so ihre Eigenheiten, und bei genauem Hinsehen, ergeben die meisten davon auch einen Sinn, auch wenn sich dieser auf den ersten Blick oft nicht gleich erschließt. :)

0
@TeeTier

Vielleicht liegt das Problem auch darin, daß viele Leute, wenn sie sich unsicher sind, eben in Systemheadern o.ä. schauen, getreu dem Motto, die Jungs müßten ja wissen, wie man es richtig macht.

Zack wird das Guarding kopiert und man hat den Salat.

Aber auch immer wieder schön:

Also, Jungs, die Verabeitung von Signalen in Eurem Programm ist unsicher und nicht Standardkonform. Der Asynchrone Handler sollte nur globale Objekte anfassen, die atomar änderbar sind, um undefinierte Inhalte und darauf basierend undefiniertes Verhalten zu vermeiden. Auch die Systemcalls (Liste) haben im Signalhandler nichts verloren, weil sie nicht reentrant sind und sie nicht in der vom Standard vorgegebenen Liste von erlaubten Syscalls steht.

Antwort dann:

... wie? Egal! Funktioniert doch, also was solls!

Da kann man dann eben nur noch mit der Schulter zucken.

1
@KarlRanseierIII

Oh ja, das sieht man leider auch unglaublich oft. Da wird ein ellenlanger Schwanz an Code mit X Seiteneffekten (sprich nicht-atomar) in die Handler gepackt, und dann wundert man sich, dass es zu Heisenbugs kommt. :)

0

(Java) Hauptklasse konnte nicht gefunden werden. Kann mir jemand helfen?

Hallo, ich bin heute von Java 1.7 (32 Bit) auf Java 1.8 (64 Bit) umgestiegen. Seitdem habe ich folgendes Problem:

Seit dem Update kann ich keine .jar Dateien mehr öffnen. Beim Doppelklick auf diese erscheint kurz die CMD mit der Meldung "Fehler: C/......../JavaFile.jar Hauptklasse konnte nicht gefunden oder geladen werden.". Ich habe mich im Internet schon intensiv damit befasst, fand aber keine Lösung.

Mit der CMD aber, kann ich die Dateien öffnen (java -jar .....) und mit Eclipse ebenso. In der voherigen Java-Version (1.7) ging dies aber auch durch Doppelklicken.

Kennt jemand das Problem und kann mir helfen?

Vielen Dank im Vorraus!, LG

...zur Frage

Wieso schreibt man Definitionen in CPP-Dateien und Deklarationen in Header-Dateien?

Mir erschließt sich irgendwie der Sinn davon nicht. Hab schon bisschen gegoogelt aber irgendwie steht überall was von Schnittstelle/Implementation und kein Wort, wieso man das macht. Könnte mir einer einfach nur den Sinn davon erklären bzw. die Vorteile, die ich davon hätte ?

...zur Frage

WWie kann ich mein Windows wipen?

Hallo. Als ich letztens Dateien von 2005 auf meinem PC gesehen habe, entschied ich dass es wohl gut sei ihn mal zu resetten.

Wenn ich jetzt bei Windows 10 in die Einstellungen -> Wiederherstellung -> diesen PC zurück setzen -> "Los Geht's" gehe dann werden einem ja 2 Optionen gegeben. Doch egal welche ich auswähle, da kommt immer der Fehler "Wiederherstellungsumgebung nicht gefunden" Jetzt ist die Frage ob ich mein Windows auch anders resetten kann? Also ich möchte alle Daten löschen, und sozusagen einen neuen PC haben. Wie das halt ist wenn man Windows das 1. mal eimrichtet, WLAN Passwort eingeben, Name, bla bla bla. Vielleicht kann mir ja jemand helfen..

...zur Frage

Kann Hamachi nicht vollständig löschen!

Hallo, ich wollte vor einiger Zeit mal wieder mit meinem Kumpel auf einem kleinen Hamachi Server Minecraft spielen. Dann wollte ich gucken, ob wir auch verbunden sind....Toll Hamachi lässt sich nicht starten, weil es ein Update will. Ok dann wollte ich das machen, aber die wollten da diese "hamachi-update.msi" haben....die war aber nicht da. "Gut, installiere ich mir eben eine neue Version" hatte ich gedacht. Naja nachdem der neue Installer meinte eine ältere Version von Hamachi gefunden zu haben und noch updaten zu müssen......wollt ihr nicht wissen wie ich darauf reagiert habe ;) Nun gut ich habe dann versucht die alte Version zu deinstallieren....und? Was meinst ihr? Hat natürlich nicht geklappt....weil er wieder dieses Update haben wollte...so habe ich überall in Foren nachgelesen...bla,bla,bla....und habe mir schließlich den "Revo Uninstaller" geholt. Der hat auch gut funktioniert, aber leider hat er irgendwie nicht alles von Hamachi gelöscht. Ein paar Dateien in dem Ordner von Hamachi sind übrig geblieben....die habe ich auch versucht zu löschen, aber vergebens...dort kam immer die Fehler Meldung: ...bla,bla,bla...Programm kann nicht gelöscht werden solange es noch geöffnet ist...bla,bla,bla....also so etwas in der Art stand dort drin...so habe ich meinen PC nochmal neugestartet...konnte ich es immer noch nicht löschen...toll...langsam wurde ich sauer! Habe dann mit allem möglichen Programmen versucht diese Dateien zu löschen, aber...könnt ihr euch ja denken. Und letzten Endes habe ich mich dazu entschieden, selber einen Forum-Eintrag zu schreiben....also jetzt!

Ich hoffe es kann mir jemand helfen...dieses Programm macht mich echt aggressiv!

...zur Frage

Kann keine wir rar datei mehr entpacken

Ich habe seit neustem ein Problem beim entpacken von .rar dateien. Und zwar schreibt mir das Programm winrar 5.11 beim entpacken folgendes:

ein beschädigter header wurde gefunden

Wie kann ich diesen Fehler beheben oder was kann ich generell machen? Ich wäre über eure hilfe dankbar.

Gruß

...zur Frage

C++ SDL2 geht nicht ---> Ich mache alles so wie erklärt!

Heyho Leute ich Programmiere derzeit mit C++ wollte jetzt mit Grafiken anfangen und habe SDL2 installiert mit Visualstudio expres 2010

Dieses Tutorial habe ich mir dazu angesehen:

https://www.youtube.com/watch?v=p62jSCqN_Bw&feature=iv&src_vid=6UlIYSLkg1M&annotation_id=annotation_217545649

Doch bei mir ist Immernoch #include Rot unterstrichen und sagt mir das der Pfad nicht Exestiert oder das SDL2 nicht aufzufinden ist.

dieses ist der Startcode den ich verwende:

include

int main(int argc, char* args[])

{ return 0; }

.

.

wen ich nun über das Rot unterstrichene #Include gehe steht dort bei mir: Error: Die Datei "Quelle" kann nicht geöffnet werden "SDL.h".

.

Ich habe beide Möglichkeiten ausgetestet main.cpp in Header Datein und einmal in Quelldatein.

Wen ihr noch Fragen habt beantworte ich diese auch!

Danke schonmal für alle antworten! :D

...zur Frage

Was möchtest Du wissen?