Nicht unbedingt: in den meisten realen Anwendungen willst du das
Ergebnis ja weiterverarbeiten. Addieren, multiplizieren, vergleichen.
Und da nützt dir ein unsigned dazwischen meist nichts.
zitter_ned_aso schrieb:> Das würde doch bei INT_MIN einen falschen Wert liefern. Weil INT_MAX ja> um 1 kleiner als |INT_MIN| (Betrag) ist.
Zumindest beim Zweierkomplement. Daher ist auf solchen Systemen
abs(INT_MIN) nicht definiert. Bei Systemen mit Einerkomplement ist es
kein Problem, da dort abs(INT_MAX) == abs(INT_MIN) == INT_MAX ist.
> Ein "unsigned int"-Wert wäre doch sinnvoller oder nicht?
Das ist so eine Sache. abs() ist schon ziemlich lange in C. Meines
Wissens war es schon in der ersten Version des ANSI-C Standards im Jahr
1989. Schon damals war bekannt dass abs(INT_MIN) ein Problem sein kann.
Das Verhalten nach 30 Jahren zu ändern? Wer weiß wie viel vorhandener
Code dann auseinander fliegt.
zitter_ned_aso schrieb:> warum hat die Funktion abs() "int" als Rückgabetyp?
Weil in den meisten Programmiersprachen, C eingeschlossen, der Datentyp
nichts mit dem Zahlenart im mathematischen Sinne zu tun hat.
Michael Gugelhupf schrieb:> Daher ist auf solchen Systemen abs(INT_MIN) nicht definiert.
Damit kann man übrigens schöne vulnerabilities bauen. Haben wir im
Studium als Übungsaufgabe bekommen (vuln finden und exploiten).
> Das Verhalten nach 30 Jahren zu ändern? Wer weiß wie viel vorhandener> Code dann auseinander fliegt.
Korrekt. Eigentlich muss man vor jeder Verwendung einer
Standard-C-Funktion die zugehörige manpage lesen und sich solcher und
ähnlicher Fallstricke bewusst sein.
man 3 abs:
> NOTES> Trying to take the absolute value of the most negative> integer is not defined.
ichWillNurRaus schrieb:> Und da nützt dir ein unsigned dazwischen meist nichts.
Schlimmer noch: UNsigned ist ANsteckend, so die Eselsbrücke. Da würde
ansonsten der ganze Ausdruck mit unsigned gerechnet.
Bastler schrieb:> zitter_ned_aso schrieb:>> warum hat die Funktion abs() "int" als Rückgabetyp?>> Weil in den meisten Programmiersprachen, C eingeschlossen, der Datentyp> nichts mit dem Zahlenart im mathematischen Sinne zu tun hat.
Aber eigentlich wählt man den Datentyp geschickterweise so, dass er den
nötigen Wertebereich auch voll unterstützt. Das ist hier nicht gegeben,
da abs(INT_MAX) eben beim Zweierkomplement auf Grund des Rückgabetyps
nicht darstellbar ist.
Jens schrieb:> Eigentlich muss man vor jeder Verwendung einer Standard-C-Funktion die> zugehörige manpage lesen und sich solcher und ähnlicher Fallstricke bewusst> sein.
Nicht unbedingt vor jeder Verwendung, denn diese Fallstricke ändern sich
ja nicht dauernd. Aber man sollte für jede Funktion wissen, welche
potenziellen Probleme es damit geben kann und diese entsprechend
berücksichtigen.
Wenn man eine Funktion nur alle 5 Jahre mal benutzt, ist es aber
natürlich besser, jedes mal nachzuschauen.
zitter_ned_aso schrieb:> warum hat die Funktion abs() "int" als Rückgabetyp?> Ein "unsigned int"-Wert wäre doch sinnvoller oder nicht?
Aus dem gleiche Grund könntest du fragen, warum die Addition und
Multiplikation zweier int-Werte wieder ein int und nicht ein long
ergeben.
In C sind alle arithmetischen Datentypen mit einer Größe von mindestens
int bzgl. aller darauf definierter Rechenoperationen abgeschlossen (bzw.
für bestimmte Operanden undefiniert). Da wäre es komisch, wenn abs eine
Ausnahme machen würde.
Yalu X. schrieb:> Aus dem gleiche Grund könntest du fragen, warum die Addition und> Multiplikation zweier int-Werte wieder ein int und nicht ein long> ergeben.
Gerade bei der Multiplikation wäre das durchaus sehr praktisch gewesen.
Auf Assembler-Ebene passiert meistens genau das: Das Ergebnis ist
doppelt so breit wie die Operanden. Aber da C das nicht auch so macht,
muss man Multiplikation dort öfter mal mit dem doppelten der eigentlich
benötigten Bitbreite durchführen, damit nicht die Hälfte des Ergebnisses
verworfen wird.
1
voidfunc(int16_ta,int16_tb)
2
{
3
// Rechnung als 16 Bit * 16 Bit, Ergebnis wird abgeschnitten
4
int32_tresult=a*b;
5
6
// korrektes Ergebnis, aber Multiplikation muss (meist unnötigerweise) in
Rolf M. schrieb:> // Rechnung als 16 Bit * 16 Bit, Ergebnis wird abgeschnitten> int32_t result = a * b;
Das kommt drauf an, was auf der jeweiligen Plattform denn die Breite von
int ist - Stichwort "integer promotion". Wenn int als 32 bit ist, wird
da nichts abgeschnitten.
Rolf M. schrieb:> Aber da C das nicht auch so macht,> muss man Multiplikation dort öfter mal mit dem doppelten der eigentlich> benötigten Bitbreite durchführen, damit nicht die Hälfte des Ergebnisses> verworfen wird.
Dass ist dann der Moment wo du hoffst, dass der Optimizer erkennt was
wirklich passieren soll und selbstständig eine 16x16 -> 32 Bit
Multiplikation einfügt.
Michael Gugelhupf schrieb:> dass der Optimizer erkennt was> wirklich passieren soll und selbstständig eine 16x16 -> 32 Bit> Multiplikation einfügt.
Das hat überhaupt nichts mit dem Optimizer zu tun und irgendeiner
magischen Erweiterung von 16 auf 32 Bit.
Die Prozesse, die im Compiler ablaufen, heißen Typ-Promotion und
Typ-Balancierung. Diese sind sehr genau definiert und keineswegs
zufällig von irgendeiner Implementierung des Optimizers abhängig.
MaWi N. schrieb:> Das hat überhaupt nichts mit dem Optimizer zu tun und irgendeiner> magischen Erweiterung von 16 auf 32 Bit.> Die Prozesse, die im Compiler ablaufen, heißen Typ-Promotion und> Typ-Balancierung. Diese sind sehr genau definiert und keineswegs> zufällig von irgendeiner Implementierung des Optimizers abhängig.
Das ist jetzt auch wieder so eine Antwort die du nur geschrieben hast um
irgend was zu sagen?
Im C Standard ist klar geregelt das der Compiler optimieren darf wenn
das Ergebnis genau so aussieht wie wenn er die vorgegebenen Abläufe
wörtlich ausführen würde.
MaWi N. schrieb:> Michael Gugelhupf schrieb:>> dass der Optimizer erkennt was>> wirklich passieren soll und selbstständig eine 16x16 -> 32 Bit>> Multiplikation einfügt.>> Das hat überhaupt nichts mit dem Optimizer zu tun und irgendeiner> magischen Erweiterung von 16 auf 32 Bit.
Doch, hat es. Du hast das Problem nur noch nicht verstanden.
> Die Prozesse, die im Compiler ablaufen, heißen Typ-Promotion und> Typ-Balancierung. Diese sind sehr genau definiert und keineswegs> zufällig von irgendeiner Implementierung des Optimizers abhängig.
Das hat auch keiner behauptet. Wenn ich aber einen 16 Bit breiten int
habe und den mit einem zweiten int multipliziere, wird eine
16-Bit-Multiplikation durchgeführt und damit ist das Ergebnis aber auch
auf 16 Bit begrenzt, selbst wenn der Prozessor eine Instruktion hat, die
daraus ein 32-Bit-Ergebnis produziert. Dann wirft der Compiler einfach
die obere Hälfte des Ergebnisses weg.
Will ich ein 32-Bit-Ergebnis, muss ich mindestens einen der Operanden
auf 32 Bit casten, obwohl ich nur eine 16x16-Bit-Multikplikation
brauche. Und dann muss ich hoffen, dass der Compiler merkt, dass der
Operand eigentlich ein 16-Bit-Wert wäre und nur auf 32 Bit gecastet
wird, damit ich auch ein 32-bit-Ergebnis bekomme.
Rolf M. schrieb:> Aber eigentlich wählt man den Datentyp geschickterweise so, dass er den> nötigen Wertebereich auch voll unterstützt.
Ein frommer Wunsch, der eine Sprache wie C zur praktischen
Nicht-Nutzbarkeit degradieren würde.
Selbst bei einer einfachen Addition müsste der Ergebnis-Datentyp um
mindestens 1-Bit größer sein, als der größte der beiden Operanden.
Der Denkfehler ist, ein C-Datentyp wie "int" wäre identisch zum
Zahlenbereich der ganzen Zahlen mit ihren Gesetzen.
Rolf M. schrieb:> Und dann muss ich hoffen, dass der Compiler merkt, dass der> Operand eigentlich ein 16-Bit-Wert wäre und nur auf 32 Bit gecastet> wird, damit ich auch ein 32-bit-Ergebnis bekomme.
Die Vorstellung, die Definition einer Programmiersprache wie C hat etwas
mit einer konkreten Implementierung für einen spezifischen Prozessor zu
tun, ist infantil.
Und ja, wenn Du in der Sprache C ein 32-Bit Ergebnis einer
16x16-Multiplikation haben willst, musst Du vorher casten. Genau so
funktioniert es eben in "C". Wie das der Compiler in Maschinensprache
umsetzt, ist in C eben nicht definiert.
Rolf M. schrieb:> Das hat auch keiner behauptet. Wenn ich aber einen 16 Bit breiten int> habe und den mit einem zweiten int multipliziere, wird eine> 16-Bit-Multiplikation durchgeführt und damit ist das Ergebnis aber auch> auf 16 Bit begrenzt
Hast Du Beitrag "Re: glibc: abs() hat int als Rückgabetyp. Warum?" nicht
gelesen oder nicht verstanden?
Bastler schrieb:> Rolf M. schrieb:>> Und dann muss ich hoffen, dass der Compiler merkt, dass der>> Operand eigentlich ein 16-Bit-Wert wäre und nur auf 32 Bit gecastet>> wird, damit ich auch ein 32-bit-Ergebnis bekomme.>> Die Vorstellung, die Definition einer Programmiersprache wie C hat etwas> mit einer konkreten Implementierung für einen spezifischen Prozessor zu> tun, ist infantil.
Allerdings ist es genauso "infantil" zu glauben, dass
Programmiersprachen, zumindest solche eher hardwarenahen wie C, völlig
losgelöst von jeglichen Hardware-Eigenschaften der üblichen
Architekturen entwickelt werden. Denn am Ende soll die Sache ja auch
performant sein.
> Und ja, wenn Du in der Sprache C ein 32-Bit Ergebnis einer> 16x16-Multiplikation haben willst, musst Du vorher casten. Genau so> funktioniert es eben in "C".
Ist das deiner Erfahrung nach auch die Art, wie es die überwiegende Zahl
der CPU-Architekturen umsetzt? Die, die ich kenne, machen es alle nicht
so.
> Wie das der Compiler in Maschinensprache umsetzt, ist in C eben nicht> definiert.
Rolf M. schrieb:> Das hat auch keiner behauptet. Wenn ich aber einen 16 Bit breiten int> habe und den mit einem zweiten int multipliziere, wird eine> 16-Bit-Multiplikation durchgeführt
Nein. Das ist so pauschal gesagt nicht richtig.
Typ-Promotion.
Rolf M. schrieb:> Wenn ich aber einen 16 Bit breiten int> habe und den mit einem zweiten int multipliziere, wird eine> 16-Bit-Multiplikation durchgeführt und damit ist das Ergebnis aber auch> auf 16 Bit begrenzt, selbst wenn der Prozessor eine Instruktion hat, die> daraus ein 32-Bit-Ergebnis produziert. Dann wirft der Compiler einfach> die obere Hälfte des Ergebnisses weg.
Falsch.
@MaWi: Ihr redet aneinander vorbei.
Rolf schrieb von einem 16 Bit breiten int, du hingegen verwendest auf
einem System mit 32 Bit breitem int ein int16_t. Auf diesem System ist
int16_t eben etwas anderes als int.
Yalu X. schrieb:> @MaWi: Ihr redet aneinander vorbei.>> Rolf schrieb von einem 16 Bit breiten int, du hingegen verwendest auf> einem System mit 32 Bit breitem int ein int16_t. Auf diesem System ist> int16_t eben etwas anderes als int.
Ja genau. Hiermit:
Rolf M. schrieb:> Wenn ich aber einen 16 Bit breiten int habe und den mit einem zweiten int> multipliziere, wird eine 16-Bit-Multiplikation durchgeführt
meinte ich nicht den Fall irgendeines 16 Bit breiten Integer-Typen,
sondern wirklich speziell den Fall, dass ich einen Compiler habe, bei
dem der Datentyp "int" 16 Bit breit ist. War vielleicht etwas
missverständlich formuliert.
Alles klar. Das war ein Missverständnis.
Vorschlag für die Zukunft:
"wenn ich einen 16 bit breiten int habe"
->
"Wenn int 16 bit breit ist"
Außerdem steht im Titel des Threads "glibc".
Soweit ich weiß, unterstützt glibc keine Microcontroller mit 16 bit int.
Rolf M. schrieb:> meinte ich nicht den Fall irgendeines 16 Bit breiten Integer-Typen,> sondern wirklich speziell den Fall, dass ich einen Compiler habe, bei> dem der Datentyp "int" 16 Bit breit ist.
Das ist in der Realität nur auf zwei Sorten von CPUs der Fall:
1) 8-Bitter, weil int mindestens 16 bit breit ist, aber da hast Du
sowieso keine 16-bit-Multiplikation in Hardware und folglich auch kein
32-bit-Ergebnis in Registern.
2) 16-Bitter, weil das der Registerbreite entspricht, und der letzte
wirklich verbreitete war der 286er. Da war das tatsächlich so, daß das
Ergebnis der Multiplikation von 16-bit-Operanden im Doppelregister DX:AX
vorlag. Allerdings konnte man damit sowieso nicht direkt weiterrechnen,
weil z.B. Addition nicht mit Doppelregistern ging.
Aber auch wenn man das auf einem 16-bitter mit dem manuellen
Operanden-Cast nach int32_t macht, heißt das keineswegs, daß die
Multiplikation selber mit 32-bit-Operanden tatsächlich so durchgeführt
wird.
C hat nämlich die "as-if-Regel". Der Compiler darf machen, was er will,
solange nur das Ergebnis identisch ist. Das bedeutet, daß er auf einem
286er das hier:
1
inta=b=300;
2
int32_tc=((int32_ta)*((int32_tb));
Sehr wohl optimieren darf zu genau dem, was ein 286er in Hardware kann.
Also die Multiplikation eben nicht mit 32-bit-Operanden ausführen,
sondern mit 16 bit, und nur das 32-bittige Ergebnis aus DX:AX in die
Variable c schieben.
Wenn der Compiler das nicht tut, ist es ein schlechter Compiler.
Nop schrieb:> 2) 16-Bitter, weil das der Registerbreite entspricht,> und der letzte wirklich verbreitete war der 286er.
Das könnte TI eventuell etwas anders sehen. Der MSP430
wird in zahlreichen Varianten seit 27 Jahren verkauft.
hmmm, mit unsigned int kommt man also auch nicht weiter. Dann muss es so
bleiben wie es ist ;-)
Es ist aber schon komisch, dass eine Funktion mit einem Rückgabetyp
arbeitet, der gar nicht in der Lage ist alles darzustellen, was aus
Funktionsparametern berechnet werden kann.
Klar, auch Rechenoperationen können zu diesem Problem führen, aber das
sind ja keine Funktionen. Das ist für mich schon was anderes. Es gibt
unendlich viele Zahlenn - es ist egal mit welchen Datentypen man
rechnet. Irgendwann wird man sowieso an die Grenzen stoßen.
Eine Funktion schränkt aber durch die Parameterliste den Zahlenberech
ein. Hier wird ja nur das Vorzeichen geändert (wenn überhaupt). Das ist
nicht sowas wie:
pow(INT_MAX, pow(INT_MAX, INT_MAX)) usw..
zitter_ned_aso schrieb:> Es ist aber schon komisch, dass eine Funktion mit einem Rückgabetyp> arbeitet, der gar nicht in der Lage ist alles darzustellen, was aus> Funktionsparametern berechnet werden kann.
Wie bereits gesagt, das ist historisch bedingt.
Die nicht-signed-int-Typen sind erst nach und nach zum Sprachumfang
hinzugekommen.
zitter_ned_aso schrieb:> Klar, auch Rechenoperationen können zu diesem Problem führen, aber das> sind ja keine Funktionen.
Natürlich sind das Funktionen. Sie unterscheiden sich von "gewöhnlichen"
Funktionen nur syntaktisch:
- Statt aus Buchstaben und Ziffern besteht ihr Name aus Sonderzeichen.
- Ihr Aufruf erfolgt in Infix- statt in Präfixnotation.
> Es ist aber schon komisch, dass eine Funktion mit einem Rückgabetyp> arbeitet, der gar nicht in der Lage ist alles darzustellen,
Ein Fall geht schief, der Rest läuft besser.
Nop hat es oben schon gesagt: unsigned ist ansteckend und versteckte
Typenwechsel mitten in einem Ausdruck sind häßlich: "abs(3) > -1" - true
or false? Und "-3 * abs(3) < 0"?
Nop schrieb:> Rolf M. schrieb:>>> meinte ich nicht den Fall irgendeines 16 Bit breiten Integer-Typen,>> sondern wirklich speziell den Fall, dass ich einen Compiler habe, bei>> dem der Datentyp "int" 16 Bit breit ist.>> Das ist in der Realität nur auf zwei Sorten von CPUs der Fall:
Dann nimm halt eine Multiplikation zweier 32-bit-Integer zu einem mit 64
Bit. Gleiches Problem, aber auch auf 32-Bit-Plattformen relevant.
> C hat nämlich die "as-if-Regel". Der Compiler darf machen, was er will,> solange nur das Ergebnis identisch ist. Das bedeutet, daß er auf einem> 286er das hier:> int a = b = 300;> int32_t c = ((int32_t a) * ((int32_t b));> Sehr wohl optimieren darf zu genau dem, was ein 286er in Hardware kann.
Ja, natürlich. Hab ich ja auch schon geschrieben, und "Michael
Gugelhupf" vor mir. Das hat keiner bestritten.
Yalu X. schrieb:> zitter_ned_aso schrieb:>> Klar, auch Rechenoperationen können zu diesem Problem führen, aber das>> sind ja keine Funktionen.>> Natürlich sind das Funktionen. Sie unterscheiden sich von "gewöhnlichen"> Funktionen nur syntaktisch:
Das stimmt nur in C++ für benutzerdefinierte Operatoren.
Rolf M. schrieb:> Das stimmt nur in C++ für benutzerdefinierte Operatoren.
Nein, Du siehst Unterschiede wo keine sind. Ja, in C kann man Operatoren
nicht neu definieren. Das ist aber nicht das Thema. Ein Operator ist nur
eine Funktion in einer anderen Schreibweise.
Ob Du nun "add(a,b)" oder "a + b" schreibst, ist per se egal. Beides
sind Funktionsaufrufe, die (mutmaßlich) zwei Parameter addieren.
Die Sprache C stellt einen festen Vorrat an Operatoren zur Verfügung, da
kannst Du als Programmierer nix ändern. In C++ kannst Du immerhin
existierenden Operatoren überladen. In anderen Sprachen kannst Du auch
neue Operatoren definieren. In wiederum anderen Sprachen kannst Du jede
Binäre Funktion in Operatorschreibweise benutzen.
Unterm Strich bleibt: Ein Operator ist nichts anderes als eine Funktion
in anderer Schreibweise, also nur ein Unterschied im Syntax.
foobar schrieb:> Ein Fall geht schief, der Rest läuft besser.
aber eigentlich könnte man ja sagen, dass das kein Problem von C ist.
Die Zweierkomplement-Darstellung hat im negativen Bereich ein Zahl
mehr. Hätten wir hier eine Symmetrie, so gebe es dieses Problem nicht.
Oder wenn wir eine Zahl mehr im positiven Bereich hätten.
Bastler schrieb:> Ein Operator ist nur eine Funktion in einer anderen Schreibweise.
Nein. Für einen Operator muss ich keinen Header mit einer Deklaration
einbinden, um ihn zu nutzen. Ich kann den selben Operator auch mit
mehreren verschiedenen Typen verwenden, obwohl C keine
Funktionsüberladung kennt. Und es gibt auch nicht die gleichen
Einschränkungen wie für den Aufruf von Funktionen, wie z.B. dass man sie
nicht außerhalb von Funktionen aufrufen kann.
1
#include<math.h>
2
3
intx=3*5;// Erlaubt, weil das Ergebnis eine Compilezeit-Konstante ist
4
doubley=sin(M_PI);// Fehler: Funktionaufrufe sind an der Stelle nicht erlaubt
5
6
intmain()
7
{
8
}
Der überwiegende Teil der Operatoren stellt auch keinen Sequenzpunkt dar
im Gegensatz zu Funktionen. Es gibt in C ziemlich viele Unterschiede
zwischen Operatoren und Funktionen.
> In C++ kannst Du immerhin existierenden Operatoren überladen.
Ja, und das sind dann wie gesagt auch tatsächlich Funktionen, für die
die gleichen Regeln gelten wie für andere Funktionen auch.
> In anderen Sprachen kannst Du auch neue Operatoren definieren. In wiederum> anderen Sprachen kannst Du jede Binäre Funktion in Operatorschreibweise> benutzen.
Mag sein, dass es Sprachen gibt, in denen es keinerlei Unterschiede
zwischen Operatoren und Funktionen gibt. C gehört aber nicht dazu.
Entschuldigung, ich wollte mit der Verwendung des Begriffs "Funktion"
keine Verwirrung stiften :)
Als ich oben "Funktion" schrieb, meinte ich damit keine C-Funktion,
sondern eine Funktion im mathematischen Sinn, also etwas, was einem oder
mehreren Argumenten ein Ergebnis zuordnet. Ich dachte, das würde aus dem
Kontext klar hervorgehen, hätte mich aber wohl dennoch etwas klarer
ausdrücken sollen.
In meinem ersten beitrag wollte ich dem TE klar machen, dass die von ihm
kritisierte Einengung des Wertebereichs von abs nichts Besonderes ist,
weil es diese Einengung in ähnlicher Weise auch bei Additionen und
Multiplikation gibt.
Daraufhin entgegnete er:
zitter_ned_aso schrieb:> Klar, auch Rechenoperationen können zu diesem Problem führen, aber das> sind ja keine Funktionen.
Er akzeptiert das Problem also bei der Addition und Multiplikation,
nicht aber bei der Absolutwertberechnung, und begründet dies damit dass
die beiden ersteren keine Funktionen seien.
Mit meiner Antwort
Yalu X. schrieb:> Natürlich sind das Funktionen.> ...
wollte ich deutlich machen, dass die Berechnung einer Summe oder eines
Produkts und die Berechnung des Absolutwerts nicht so unterschiedlich
sind, dass daraus die Forderung abgeleitet werden könnte, dass die
abs-Funktion für gesamten Argumentwertebereich definiert sein muss.
Addition und Multiplikation sind natürlich keine Functions im Sinne der
Sprachspezifikation von C (das können sie schon allein deswegen nicht
sein, weil ihr Name kein gültiger C-Identifier ist). Es sind aber sehr
wohl Funktionen in dem Sinne, dass sie aus einem oder mehreren (im
konkreten Fall zwei) Zahlenwerten einen Ergebniswert berechnen. Dass sie
sich von C-Funktionen in einigen Punkten (wie bspw. Sequenzpunkten)
unterscheiden, ist bei der Betrachtung der eigentlichen Berechnung und
der Wertebereiche (um die es in diesem Thread ja ausschließlich geht)
IMHO völlig irrelevant.
abs() wäre so im mathematichen Sinne keine Funktion. Da es ja im
Definitionsbereich eine Zahl INT_MIN gibt, zu der es keinen
Funktionswert abs(INT_MIN) gibt.
zitter_ned_aso schrieb:> abs() wäre so im mathematichen Sinne keine Funktion. Da es ja im> Definitionsbereich eine Zahl INT_MIN gibt, zu der es keinen> Funktionswert abs(INT_MIN) gibt.
Das ist jetzt aber ein schräger Schluss :)
Andersherum wird ein Schuh daraus:
Da der Funktionswert von INT_MIN nicht definiert ist, gehört INT_MIN
nicht zum Definitionsbereich.
zitter_ned_aso schrieb:> abs() wäre so im mathematichen Sinne keine Funktion. Da es ja im> Definitionsbereich eine Zahl INT_MIN gibt, zu der es keinen> Funktionswert abs(INT_MIN) gibt.
So was nennt man glaub "partielle Funktion". Also eine Funktion die
nicht für alle Eingangswerte ein Ergebnis liefert bzw. definiert ist.
Eine "totale Funktion" wäre dann für alle denkbaren Eingangswerte
definiert.
Rolf M. schrieb:> Es gibt in C ziemlich viele Unterschiede> zwischen Operatoren und Funktionen.
Naja, die Unterschiede sind doch aber nicht von fundamentaler Natur.
Bei einem guten Glas Wein betrachtet sind Operatoren nichts anderes als
syntaktischer Zucker für Programmierer. Ohne Operatoren hätten wir
vielleicht:
Rolf M. schrieb:> Auf Assembler-Ebene passiert meistens genau das: Das Ergebnis ist> doppelt so breit wie die Operanden.
Vor Äonen war das so.
Bei einem gepipelinenten Multiplizierer ist es jedoch sinnvoller,
zweimal zu multiplizieren, einmal für die untere und einmal für die
obere Hälfte, als beides zusammen zu rechnen. Grund ist das
Ressourcenmanagement von Bussen und Registern.
Das war schon bei PowerPC so, anders als in IBMs POWER. Und die
meistgebrauchten Multiplikationsbefehle bei x86 liefern nur die untere
Hälfte. 32bit ARM hatte anfangs überhaupt nur diese Variante.