cstblib abs

Status
Dieses Thema wurde gelöst! Zur Lösung gehen…

schiese

Erfahrenes Mitglied
Hallo,

ich habe mir gerade die Templates angeschaut und bin dann nebenbei auf eine Frage bezüglich der abs-Funktion aus cstdlib gestoßen. Die Funktion ist nach Cpp reference nur für integrale Datentypen definiert. Mein Code sieht jetzt wie folgt aus
C++:
#include <iostream>
#include <cstdlib>

template <typename T>
bool kleiner(const T& a, const T& b) {
    return a < b;
}

template <>
bool kleiner<double>(const double& a, const double& b) {
    std::cout << "Drin im spezialisierten Template\n\n";
    return std::abs(a) < std::abs(b);
}

std::cout << (kleiner(10.4,10.5) ? 10.4 : 10.5);

Das für mich nicht nachvollziehbare ist, dass der Code ein richtiges Ergebnis liefert. Ich kann die Argumente beim Funktionsaufruf vertauschen und das Ergebnis der Funktion ist auch richtig. Wie kann es sein, da die abs-Funktion aus cstdlib nur für integrale Datentypen definiert ist? Im spazialisierten Template bin ich (die entsprechende Funktion wird vom Compiler erzeugt), da ich die Ausgabe auf der Konsole erhalte. Ich nutze den GCC mit dem C++14 Standard.
 

Technipion

Erfahrenes Mitglied
Müsste ich dafür nicht cmath einbinden?
Nö, wieso? Es ist ebenfalls in cstdlib definiert...

Guckst du hier: Standard library header <cstdlib> - cppreference.com
Ganz unten bei Synopsis:
C:
...
// absolute values
  int abs(int j);
  long int abs(long int j);
  long long int abs(long long int j);
  float abs(float j);
  double abs(double j);
  long double abs(long double j);
  long int labs(long int j);
  long long int llabs(long long int j);
...
 

schiese

Erfahrenes Mitglied
Okay. Überzeugt :)
Aber etwas verwirrt bin ich schon. Wenn ich mir nur die Methodenübersicht angucke, steht da doch eindeutig:

Code:
abs(int)   (C++11) computes absolute value of an integral value (|x|) (function)
labs
llabs
In der Zusammenfassung unten sind dann doch die Methodendeklarationen für double und float zu sehen. Wieso steht dann oben explizit abs(int) :unsure: Und ich meine mal auf einer anderen Seite gelesen zu haben, dass die abs-Funktion aus cstdlib nur für integrale Datentypen ist und die abs-Funktion aus cmath für Gleitkommazahlen.
 

Technipion

Erfahrenes Mitglied
Wieso steht dann oben explizit abs(int) :unsure:
Leider ist cppreference.com nicht immer die zuverlässigste Quelle ;)
Für das meiste ist die Seite okay. Aber bei tiefgreifenden Verständnisfragen ist es wie mit Wikipedia; der Teufel liegt halt im Detail.

ABER: Gerade für solche tiefgreifenden Verständnisfragen gibt es einen tollen kleinen Trick in der Toolkiste. Schau dir doch einfach mal an, was eigentlich mit deinem Code beim Compilieren passiert. Ich habe dein Programm von oben genommen:
C++:
// main.cpp

#include <iostream>
#include <cstdlib>

template <typename T>
bool kleiner(const T& a, const T& b) {
    return a < b;
}

template <>
bool kleiner<double>(const double& a, const double& b) {
    std::cout << "Drin im spezialisierten Template\n\n";
    return std::abs(a) < std::abs(b);
}

int main() {
    std::cout << (kleiner(10.4,10.5) ? 10.4 : 10.5);
    return 0;
}
Und mit g++ main.cpp -o main.bin && ./main.bin getestet, dass auch alles funktioniert. Tut es.
Und dann habe ich mittels cpp main.cpp -o main_full.cpp "nur" den Preprocessor drüberlaufen lassen. Die neue Datei main_full.cpp ist quasi das, was der eigentliche C++-Compiler verfüttert bekommt. Alle Präprozessor-Befehle (#include, #define, etc.) sind darin schon abgearbeitet.
Dann habe ich in main_full.cpp einfach mal nach "abs(" gesucht. Bei mir geht es ab Zeile 16988 los:
C++:
// ...

# 34 "/usr/include/c++/8/bits/std_abs.h" 3
# 46 "/usr/include/c++/8/bits/std_abs.h" 3
extern "C++"
{
namespace std __attribute__ ((__visibility__ ("default")))
{


  using ::abs;


  inline long
  abs(long __i) { return __builtin_labs(__i); }



  inline long long
  abs(long long __x) { return __builtin_llabs (__x); }







  inline constexpr double
  abs(double __x)
  { return __builtin_fabs(__x); }

  inline constexpr float
  abs(float __x)
  { return __builtin_fabsf(__x); }

  inline constexpr long double
  abs(long double __x)
  { return __builtin_fabsl(__x); }



  inline constexpr __int128
  abs(__int128 __x) { return __x >= 0 ? __x : -__x; }
# 100 "/usr/include/c++/8/bits/std_abs.h" 3
  inline constexpr
  __float128
  abs(__float128 __x)
  { return __x < 0 ? -__x : __x; }

//...
Wie du siehst, haben es die double-/float-Versionen von abs in den fertigen Code geschafft, obwohl "nur" cstdlib included wurde.

Die Datei enthält natürlich noch viel mehr interessantes Zeug. Aber dies sei dem Leser als Übung überlassen :p

Gruß Technipion
 

schiese

Erfahrenes Mitglied
Und dann habe ich mittels cpp main.cpp -o main_full.cpp "nur" den Preprocessor drüberlaufen lassen. Die neue Datei main_full.cpp ist quasi das, was der eigentliche C++-Compiler verfüttert bekommt. Alle Präprozessor-Befehle (#include, #define, etc.) sind darin schon abgearbeitet.
Das war mir neu. Vielen Dank dafür :) Da stehen ja eine Menge interessanter Informationen drin.
 
Status
Dieses Thema wurde gelöst! Zur Lösung gehen…

Neue Beiträge