Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Kapselung von #ifdefs ?

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
18.03.2009, 17:12 Uhr
~EinFragender
Gast


Hallo,

ich bin gerade darauf gestoßen dass man vielleicht #ifdefs kapseln sollte in einer separaten Datei - also in etwa so:


C++:
//in der main.cpp z.B.

// Also hier wird nur 1 variante includiert mit allen Methoden... Die Dateien
// stehen unten implementiert.
#ifdef MEIN_FLAG
#   include "variante_1.hpp"
#else
    inlude "variante_2.hpp"
#endif


int main()
{
    int a = get_a();
}






C++:
//variante_1.hpp
int get_a()
{
   return 2;
}


//variante_2.hpp
int get_a()
{
   return 3;
}



Fragen:
======

1) Macht diese Methode auch Sinn wenn man von vornherein weiß dass man nur 1 Flag hat oder nicht. Also entweder das Flag wird gesetzt mit MEIN_FLAG oder eben nicht. ?

2) Wie sieht es mit der Performance aus? Macht sich das bemerkbar? Ich muss ja praktisch für jede compilerabhängige anweisung bzw. jeden block eine methode schreiben in der verschiedenen parameter übergeben werden. Ist das performance-mässig bremsend oder bemerke ich das wohl net am ende?

3) Verfährt ihr so mit bedingter Compilierung? Wenn nciht - wie macht ihr es dann? Über den üblichen weg einfach die #ifdefs zu lassen?

Danke euch
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
18.03.2009, 18:43 Uhr
0xdeadbeef
Gott
(Operator)


Definitionen haben im Header nichts verloren, also

C++:
// get_a.hpp
#ifndef INCLUDED_GET_A_HPP
#define INCLUDED_GET_A_HPP

int get_a();

#endif



C++:
// get_a.cpp
#include "get_a.hpp"

int get_a() {
#ifdef MEIN_FLAG
  return 2;
#else
  return 3
#endif
}



C++:
// main.cpp
#include "get_a.hpp"

int main() {
  int a = get_a();
}


...wobei ich in diesem speziellen Fall wohl eher

C++:
// main.cpp

int main() {
  int a = NUM_A;
}


schreiben und NUM_A beim Kompilieren als 2 oder 3 definieren würde.

Ob #ifdef hierfür Sinn macht, hängt im Wesentlichen davon ab, wie groß die Unterschiede zwischen den zwei Varianten sind. Wenn sie im Grunde gleich sind und sich nur in ein oder zwei Zeilen unterscheiden, ist #ifdef sinnvoll. Wenn es zwei grundverschiedene Dinge sind, kann man darüber nachdenken, sie stattdessen in zwei getrennten Quellcodedateien zu implementieren und das Buildsystem die richtige aussuchen zu lassen.

Auf die Performance wirkt sich das nicht aus, denn zur Laufzeit sind die #ifdefs samt nicht kompiliertem Code längst verschwunden. Der Präprozessor wird zur Compilezeit vielleicht ein paar Mikrosekunden länger zu tun haben.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
19.03.2009, 12:59 Uhr
~EinFragender
Gast


Erstmal danke für die Antwort. Leider verstehe ich dich nicht allzusehr deadbeef.


Zitat:
Definitionen haben im Header nichts verloren, also


Du schreibst doch gerade die ifdefs in einen header *.hpp oder nicht?Oder meinst du die ifdefs sollten nicht oben in der main auftauchen?

Prinzipiell war das von mir genannte beispiel nur ein sehr einfaches. Ich möchte code schreiben der über SHMEM oder OpenMP (parallel) läuft und entweder parallel oder seriell kompiliert werden soll. Das sind glaube ich schon zwei verschiedene dinge.

So wie ich das verstehe machst Du ja mit dem von dir genannten beispiel dann statt 2 Methoden (eine für jeweils ein compilat) nur eine mit der verzweigung #ifdef wieder in der get_a() methode.

Somit lagerst Du doch nur das Problem aus...wenn ich jetzt wieder in der Methode am anfang ifdefs habe, dann wieder code den beide gemeinsam haben, dann wieder ifdefs wäre das doch wieder wie wenn ich die ifdefs einfach in den code an sich (z.B. main) schreibe oder nicht?

Ich glaube ich habe Dich missverstanden....

Wie würdest Du das bei einem Projekt (~10k Zeilen) machen wenn Du 2 Flags hättest.

Und noch mehr die frage. Wie soll so etwas bei Debug-Code gehen? Ein Makro schreiben? Wie verfährst Du da?

Danke
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
19.03.2009, 22:06 Uhr
0xdeadbeef
Gott
(Operator)


Du kannst nicht die gesamte Definition einer Funktion in den Header packen, das fliegt dir auseinander, sobald du den Header mehr als einmal einbindest - #include ist ja einfache Textersetzung, das heißt, der Compiler kompilierte in dem Fall die Funktion zweimal, und der Linker wüsste danach nicht, welches der beiden Kompilate er verwenden sollte.

In den Header kommt lediglich die Deklaration, und die ist in beiden Fällen gleich. Sie muss gleich sein, denn der verwendende Code erwartet das gleiche Interface. Dementsprechend macht es wenig Sinn, ein #ifdef um #includes zu setzen.

Ich habe im Beispiel oben get_a in Deklaration und Definition aufgeteilt - Deklaration im Header, wie üblich, der dann auch von der main.cpp eingebunden wird, und Definition mit #ifdefs in einer eigenen Übersetzungseinheit. Welcher Code am Ende genommen wird, hängt davon ab, ob MEIN_FLAG bei der Kompilierung von get_a.cpp definiert ist oder nicht.

Wenn sich der Code der beiden get_a-Funktionen komplett unterscheidet, kann es aber Sinn machen, die beiden Varianten komplett voneinander zu trennen. Etwa so:

C++:
// get_a_2.cpp
#include "get_a.hpp"

int get_a() { return 2; }



C++:
// get_a_3.cpp
#include "get_a.hpp"

int get_a() { return 3; }


und dann im Build-System zu unterscheiden. Für eine Makefile beispielsweise:

make:

#!/usr/bin/make

OBJS = main.o get_a_2.o
ifeq ($(VARIANTE),3)
  OBJS = main.o get_a_3.o
endif

program: $(OBJS)
  $(CXX) $(CXXFLAGS) -o $@ $<


und dann per

Shell:

$ make VARIANTE=3


kompilieren, falls get_a_3.cpp verwendet werden soll.

Außerdem wäre eine Entscheidung zur Laufzeit unter Verwendung eines Funktionszeigers oder gar eine Plugin-Architektur mit shared objects denkbar.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
20.03.2009, 11:01 Uhr
~EinFragender
Gast


Also erstmal danke für die ausführliche Antwort.


Zitat:
Außerdem wäre eine Entscheidung zur Laufzeit unter Verwendung eines Funktionszeigers


das hört sich sehr interessant an. Ich weiß zwar (noch) nicht wie das gehen soll aber vielleicht hat jemand ein kurzes beispiel....ich bin schon auf der suche nach informationen im web...

Danke
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
23.03.2009, 14:37 Uhr
~EinFragender
Gast


Und wie sieht es da mit Debug-Information aus? Schreibt ihr (Du) die debug-info "normal" über #ifdef mitten in den code?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
23.03.2009, 15:35 Uhr
0xdeadbeef
Gott
(Operator)


Das mit dem Funktionszeiger ist im Grunde nicht weiter schwierig, die Syntax ist aber etwas gewöhnungsbedürftig. Das funktioniert etwa so:

C++:
#include <iostream>

void hallo() { std::cout << "Hallo!" << std::endl; }
void hallo_welt() { std::cout << "Hallo, Welt!" << std::endl; }

int main() {
  void (*func)() = hallo;
  func();
  func = hallo_welt;
  func();
}


Der fett markierte Teil deklariert func als einen Zeiger auf eine Funktion vom Typ void(). Es ist in diesem Zusammenhang ziemlich üblich, sich ein Alias für den Funktionstypen zurechtzulegen, etwa so:

C++:
#include <iostream>

void hallo() { std::cout << "Hallo!" << std::endl; }
void hallo_welt() { std::cout << "Hallo, Welt!" << std::endl; }

int main() {
  typedef void (*func_t)();
  func_t func = hallo;

  func();
  func = hallo_welt;
  func();
}


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
23.03.2009, 16:57 Uhr
~EinFragender
Gast


Vielen Dank deadbeef - wieder was dazugelernt. Aber müsste man dann nicht dennoch wenn wir auf meine ausgangsfrage zurückkommen mit #ifdef #else #endif unterscheiden ob func_t auf hallo() oder hallo_welt() gesetzt wird? Dann wären wir wieder bei meiner ausgangsfrage mit der kapselung der ifdefs. Oder habe ich was falsch verstanden?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
23.03.2009, 18:46 Uhr
0xdeadbeef
Gott
(Operator)


Mit dem Funktionszeiger kannst du locker zur Laufzeit unterscheiden, welche Funktion benutzt werden soll. Zum Beispiel:

C++:
#include <iostream>

void hallo() { std::cout << "Hallo!" << std::endl; }
void hallo_welt() { std::cout << "Hallo, Welt!" << std::endl; }

int main() {
  typedef void (*func_t)();
  int x;
  func_t funcs[] = { hallo, hallo_welt };

  std::cout << "(0) Hallo\n(1) Hallo, Welt\nAuswahl: " << std::flush;
  std::cin >> x;

  funcs[x]();
}


...Fehlerbehandlung ist als Übungsaufgabe dem Leser überlassen. In deinem Fall liefe das wohl auf etwas wie

C++:
  if(use_openmp) {
    func = func_openmp;
  } else {
    func = func_shmem;
  }


hinaus, wonach der Rest der Welt func benutzt. Das ganze macht natürlich nur dann wirklich Sinn, wenn die Funktionsauswahl von der Zielmaschine abhängt.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
25.03.2009, 15:14 Uhr
~EinFragender
Gast


Danke erneut.


Zitat:
Das ganze macht natürlich nur dann wirklich Sinn, wenn die Funktionsauswahl von der Zielmaschine abhängt.


Puh...ich rätsele was Du damit meinst. Meinst Du damit dass es vom OS abhängt? Oder von der Architektur. Mir ist das leider nicht klar...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: