Liebe Leserinnen, liebe Leser,

in diesem Beitrag teile ich meine Gedanken über kleine Themen, wie Header-Dateierweiterungen und Compilerflaggen. Diese Themen sind nicht ein Beitrag wert, aber weil sie große Probleme bewirken können (trotz ihre alltägliche Natur), lohnt es sich darüber zu diskutieren. Lasst uns einen Ausschnitt einer Fehlermeldung des Compilers untersuchen:

Make

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::ToolbarDrawer()':
/usr/include/opencv2/core/mat.inl.hpp:404: multiple definition of `ToolbarDrawer::ToolbarDrawer()'
CMakeFiles/tutprog.dir/main.cpp.o:/usr/include/opencv2/core/mat.inl.hpp:404: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::ToolbarDrawer()':
/usr/include/opencv2/core/mat.inl.hpp:404: multiple definition of `ToolbarDrawer::ToolbarDrawer()'
CMakeFiles/tutprog.dir/main.cpp.o:/usr/include/opencv2/core/mat.inl.hpp:404: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::getToolbarCols() const':
./ToolbarDrawer.cpp:22: multiple definition of `ToolbarDrawer::getToolbarCols() const'
CMakeFiles/tutprog.dir/main.cpp.o:./ToolbarDrawer.cpp:22: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::getToolbarRows() const':
./ToolbarDrawer.cpp:27: multiple definition of `ToolbarDrawer::getToolbarRows() const'
CMakeFiles/tutprog.dir/main.cpp.o:./ToolbarDrawer.cpp:27: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::selectDrawingShape(cv::Point_<int> const&)':
./ToolbarDrawer.cpp:32: multiple definition of `ToolbarDrawer::selectDrawingShape(cv::Point_<int> const&)'
CMakeFiles/tutprog.dir/main.cpp.o:./ToolbarDrawer.cpp:32: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::setToolbarBackground()':

...

collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/tutprog.dir/build.make:216: tutprog] Error 1
make[1]: *** [CMakeFiles/Makefile2:68: CMakeFiles/tutprog.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

Die Auslassungspunkte verstecken mehr vom Gleichen, tatsächlich etliche Seiten mehr. Nachdem man dieser Strom von Fehlermeldungen begegnet, würde man sofort die Quelldateien zu durchlesen starten, um nach Neudefinierungen zu suchen. Die überrachende Sache ist, dass man mit hoher Wahrscheinlichkeit keine Neudefinierungen finden wird. Was ist das Problem dann? Alles scheint in Ordnung zu sein. Vielleicht hatten wir nach dem Grund am falschen Fleck gesucht? Lasst und den folgenden Codeausschnitt untersuchen, um den Hintergrund besser zu verstehen:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "CanvasDrawer.hpp"
#include "ToolbarDrawer.hpp"
#include "ButtonDrawer.hpp"
#include <opencv2/core/mat.hpp>
#include <opencv2/core/types.cpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/video.hpp>
#include <string>

class MyClass {
public:
    MyClass();
    MyClass(cv::Mat stuff, int x, int y);
    
    int getXCoord() const;
    int getYCoord() const;
    void setXCoord(int x);
    void setYCoord(int y);
    cv::Mat& theStuff();
    
private:
    cv::Mat mStuff;
    int xCoord;
    int yCoord;
};

Haben Sie den Fehler bemerkt? Sage und schreibe, dieser Code ist genug, die obengenannte Fehlermeldung zu erstellen. Der gleiche Code mit kleinen Änderungen ist unten zu sehen:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "CanvasDrawer.h"
#include "ToolbarDrawer.h"
#include "ButtonDrawer.h"
#include <opencv2/core/mat.h>
#include <opencv2/core/types.cpp>
#include <opencv2/core/utility.h>
#include <opencv2/imgproc.h>
#include <opencv2/video.h>
#include <string>

class MyClass {
public:
    MyClass();
    MyClass(cv::Mat stuff, int x, int y);
    
    int getXCoord() const;
    int getYCoord() const;
    void setXCoord(int x);
    void setYCoord(int y);
    cv::Mat& theStuff();
    
private:
    cv::Mat mStuff;
    int xCoord;
    int yCoord;
};

Ich gebe zu, dass das noch nicht ganz klar ist, aber das Problem ist viel sichtbarer als früher. Das wird mit weitaus geringeren Wahrscheinlichkeit passieren, dass man drei Buchstaben tippt, wenn nur ein einziges notwendig ist. Meiner Meinung nach ähneln hpp und cpp sich zu viel, und während einer schwacher Sekunde des Tages könnte man den letzteren anstatt des vorigeren tippen. Natürlich, wenn man vorhandene Bibliotheken benutzt, gibt es keine Alternative, aber wenn man Alternative hat, würde ich die .h Dateierweiterung bevorzugen.

Thema 2

Ein anderes Thema ist heute die Flaggen, mit denen unsere Projekte kompiliert werden. Wenn man eine CMake-Datei schnell erstellt, um etwas mit möglichst geringerem Aufwand zu komilieren (und weil wir nur ein Übungsprojekt kompilieren), könnte man das denken, dass eine ausgelassene Flagge nicht viel schaden kann. Leider, trotz (mal wieder) der banalen Natur der Sache können die Folgen ganz schwer sein:

CMake

1
2
3
4
5
# ...

set (CMAKE_CXX_FLAGS "-g -Og ${CMAKE_CXX_FLAGS}")

# ...

Was könnte schief gehen? Kleine Optimierungen wurden eingeschaltet, die die Fehlersuche nicht betreffen, und Debugsymbole stehen auch zur Vefügung. Der Code kann nach Bedarf kompiliert und ausgetestet werden. Das ist sicherlich wahr, aber: Ist das wirklich nötig, den Debugger sofort auszuführen, falls etwas schief geht? Zum Beispiel, nachdem ich eine kleine Razionalisierung gemacht habe, startete eines meiner Lernprojekte plötzlich abzustürzen, und trotz aller Versuche, einen Fehler in der Logik zu finden, habe ich kein Problem gefunden. Genauso wie bei dem ersten Thema dieses Beitrags enthielt die Programmlogik keine Fehler, stattdessen war das Problem etwas Banales: Ich habe durch eine Funktion mit einem nicht void Rückgabewert durchgefallen. Man könnte das erwarten, dass solche Sachen das Kompilierverfahren standardmäßig unterbrechen würden, aber offensichtlich ist das nicht so. GCC wird gar nichts sagen, es sei denn, man bittet explizit den Compiler durch zusätzliche Flaggen gesprächig zu sein:

CMake

1
2
3
4
5
6
# ...

# -Weffc++ can also be included for some Scott Meyers wisdom
set (CMAKE_CXX_FLAGS "-g -Og -Wall -Wextra -Wshadow ${CMAKE_CXX_FLAGS}")

# ...

Wenn diese eingeschaltet werden, bekommt man Warnungen über Durchfälle, die bestimmt helfen.

Die Lektionen des Tages sind:

Thema 1:

Echte Probleme stammen nicht immer aus Logikfehler, manchmal verursachen Tippfehler gleichermaßen große Schaden.

Thema 2:

Man sollte keine Fehlermeldungen erwarten (ungeachtet der Wichtigkeit), es sei denn, man schaltet sie explizit ein.