Warum wird der ternäre Operator verwendet, um 1 und 0 in einem Makro zu definieren?
Lesezeit: 8 Minuten
Viktor S
Ich verwende ein SDK für ein eingebettetes Projekt. In diesem Quellcode habe ich Code gefunden, den ich zumindest merkwürdig fand. An vielen Stellen im SDK gibt es Quellcode in diesem Format:
Macht die Verwendung des ternären Operators hier einen Unterschied?
Ist nicht
#define FOO (1 > 0)
das Gleiche wie
#define BAR ( (1 > 0) ? 1 : 0)
?
Ich habe versucht, es mit auszuwerten
printf("%d", FOO == BAR);
und erhalten das Ergebnis 1, also scheinen sie gleich zu sein. Gibt es einen Grund, den Code so zu schreiben, wie sie es getan haben?
Nein, es gibt keinen Grund. Sie haben Recht.
– Kunst
31. März 2017 um 11:08 Uhr
Teilweise Off-Topic: Wann hört der Wahnsinn der Nutzung des Präprozessors auf? Hier liegt eine potentielle Mehrfachauswertung der beteiligten Funktionen vor. Einfach unnötig.
– Stefan
31. März 2017 um 13:29 Uhr
Manchmal ist es auch schön, explizit zu sein. Der ternäre Operator hier macht auf einen Blick deutlich, dass der Zweck des Makros darin besteht, einen booleschen Wert zurückzugeben.
Sieht aus wie die Art von CI, die vor langer Zeit geschrieben wurde. Ich war von Pascal zu C gekommen, der eine dedizierte hatte boolean Typ, also verschwendete ich unzählige Zeit damit, Horror zu ändern if (n) zu if (0 != n), wahrscheinlich fügt er eine zweifelhafte Besetzung hinzu, “um sicherzugehen”. Ich bin mir sicher, dass ich kugelsichere Ungleichungen mag if (a < b) ..., zu. Klar sah wie bei Pascal if a < b then ...aber das wusste ich Cs< war kein boolean aber ein intund ein int könnte sein fast alles! Angst führt zu Vergoldung, Vergoldung führt zu Paranoia, Paranoia führt zu… solchem Code.
– Kevin J. Chase
1. April 2017 um 22:06 Uhr
Bathseba
Sie haben Recht, in C ist es tautolog. Sowohl Ihre besondere ternäre Bedingung und(1 > 0) sind vom Typ int.
Aber es möchten in C++ jedoch in einigen merkwürdigen Eckfällen (z. B. als Parameter für überladene Funktionen) von Bedeutung, da Ihr ternärer bedingter Ausdruck vom Typ ist intwohingegen (1 > 0) ist vom Typ bool.
Ich vermute, dass der Autor sich darüber Gedanken gemacht hat, um die C++-Kompatibilität zu erhalten.
ich dachte bool <-> int Konvertierungen sind in C++ durch §4.7/4 aus dem Standard implizit (ganzzahlige Konvertierung), also wie würde es ausfallen?
– Motun
31. März 2017 um 11:22 Uhr
Betrachten Sie zwei Überladungen einer Funktion fooman nimmt a const bool& der andere nimmt a const int&. Einer von ihnen bezahlt Sie, der andere formatiert Ihre Festplatte neu. Möglicherweise möchten Sie sicherstellen, dass Sie in diesem Fall die richtige Überladung aufrufen.
– Bathseba
31. März 2017 um 11:23 Uhr
wäre es nicht offensichtlicher, diesen Fall zu behandeln, indem Sie das Ergebnis in umwandeln int anstatt die ternäre zu verwenden?
– Martinkunew
31. März 2017 um 13:39 Uhr
@Bathsheba Obwohl es sich um einen legitimen Eckfall handelt, ist jeder Programmierer, der integrale Überladungen verwendet, um ein solches inkonsistentes Verhalten zu implementieren, völlig böse.
– JAB
31. März 2017 um 13:53 Uhr
@JAB: Sie müssen nicht böse sein, Sie müssen nur den (häufigen) Fehler machen, einen Code zu schreiben, der versehentlich zwei verschiedene Dinge tut (oder schlimmer noch, aufrufen undefiniertes Verhalten) abhängig vom Integraltyp und haben das Unglück, dies an einer Stelle zu tun, die radikal unterschiedliche Codepfade auslösen kann.
– Benutzer1084944
1. April 2017 um 5:39 Uhr
entspannen
Es gibt Linting-Tools, die der Meinung sind, dass das Ergebnis eines Vergleichs boolesch ist und nicht direkt in der Arithmetik verwendet werden kann.
Ich sage nicht, dass sie Recht haben, aber es ist eine mögliche Erklärung dafür, warum der Code so geschrieben wurde.
Not to name names or point any fingers, aber du hast irgendwie beides gemacht, lol.
– Stapelüberlauf
31. März 2017 um 14:41 Uhr
zwöl
Sie werden dies manchmal in sehen sehr alt Code, bevor es einen C-Standard gab, um das zu buchstabieren (x > y) wird als Zahl 1 oder 0 ausgewertet; Einige CPUs würden dies lieber auf -1 oder 0 auswerten lassen, und einige sehr alt Compiler sind vielleicht einfach mitgekommen, daher hatten einige Programmierer das Gefühl, dass sie die zusätzliche Abwehr benötigen.
Sie werden dies manchmal auch sehen, weil ähnlich Ausdrücke nicht unbedingt als Zahl 1 oder 0 auswerten. Zum Beispiel in
das Innere &-Ausdruck ergibt entweder 0 oder den numerischen Wert von F_DO_GRENFELZwas wahrscheinlich ist nicht 1, also die ? 1 : 0 dient der Kanonisierung. Ich persönlich denke, es ist klarer, das als zu schreiben
aber vernünftige Menschen können anderer Meinung sein. Wenn Sie eine ganze Reihe davon hintereinander hätten und verschiedene Arten von Ausdrücken testen würden, hätte jemand vielleicht entschieden, dass es pflegeleichter ist, sie zu setzen ? 1 : 0 am Ende von alle von ihnen, als sich Gedanken darüber zu machen, welche es tatsächlich brauchten.
Im Großen und Ganzen verwende ich lieber !!( expr ) um einen booleschen Wert zu kanonisieren, aber ich gebe zu, dass es verwirrend ist, wenn Sie nicht damit vertraut sind.
– PJTrail
5. April 2017 um 17:41 Uhr
@PJTraill Jedes Mal, wenn Sie Leerzeichen in Ihre Klammern einfügen, tötet Gott ein Kätzchen. Bitte. Denken Sie an die Kätzchen.
– zol
6. April 2017 um 16:19 Uhr
Das ist der beste Grund, warum ich gehört habe, in einem C-Programm keine Leerzeichen in Klammern zu setzen.
– PJTrail
6. April 2017 um 21:57 Uhr
Konchog
Es gibt einen Fehler im SDK-Code, und der Dreier war wahrscheinlich ein Knüppel, um ihn zu beheben.
Da es sich um ein Makro handelt, können die Argumente (alpha_char) beliebige Ausdrücke sein und sollten in Klammern gesetzt werden, da Ausdrücke wie ‘A’ && ‘c’ den Test nicht bestehen.
@CiaPan macht einen wichtigen Punkt im folgenden Kommentar, nämlich dass die mehr als einmalige Verwendung eines Parameters zu undefinierbaren Ergebnissen führt. Zum Beispiel
#define IS_LOWER( x ) (((x) >= 'a') && ((x) <= 'z'))
char ch="y";
std::cout << IS_LOWER(ch++);
**1**
**BUT ch is now '{'**
PSkocik
In C spielt es keine Rolle. Boolesche Ausdrücke in C haben Typ int und ein Wert, der entweder ist 0 oder 1Also
ConditionalExpr ? 1 : 0
hat keine Wirkung.
In C++ ist es praktisch eine Umwandlung in intda bedingte Ausdrücke in C++ einen Typ haben bool.
#include <stdio.h>
#include <stdbool.h>
#ifndef __cplusplus
#define print_type(X) _Generic(X, int: puts("int"), bool: puts("bool") );
#else
template<class T>
int print_type(T const& x);
template<> int print_type<>(int const& x) { return puts("int"); }
template<> int print_type<>(bool const& x) { return puts("bool"); }
#endif
int main()
{
print_type(1);
print_type(1 > 0);
print_type(1 > 0 ? 1 : 0);
/*c++ output:
int
int
int
cc output:
int
bool
int
*/
}
Es ist auch möglich, dass kein Effekt beabsichtigt war und der Autor einfach dachte, dass es den Code klarer macht.
Übrigens, ich denke, C sollte der Suite folgen und boolesche Ausdrücke machen _Booljetzt, wo C hat _Bool und _Generic. Es sollte nicht viel Code brechen, da alle kleineren Typen automatisch hochgestuft werden int jedenfalls in den meisten Zusammenhängen.
– PSkočik
31. März 2017 um 11:44 Uhr
Eine einfache Erklärung ist, dass einige Leute entweder nicht verstehen, dass eine Bedingung denselben Wert in C zurückgeben würde, oder dass sie denken, dass es sauberer zu schreiben ist ((a>b)?1:0).
Das erklärt, warum einige ähnliche Konstrukte auch in Sprachen mit richtigen Booleschen Werten verwenden, was in C-Syntax der Fall wäre (a>b)?true:false).
Dies erklärt auch, warum Sie dieses Makro nicht unnötig ändern sollten.
Übrigens, ich denke, C sollte der Suite folgen und boolesche Ausdrücke machen _Booljetzt, wo C hat _Bool und _Generic. Es sollte nicht viel Code brechen, da alle kleineren Typen automatisch hochgestuft werden int jedenfalls in den meisten Zusammenhängen.
– PSkočik
31. März 2017 um 11:44 Uhr
J. Guarin
Vielleicht würde es als eingebettete Software einige Hinweise geben. Vielleicht gibt es viele Makros, die in diesem Stil geschrieben wurden, um leicht darauf hinzuweisen, dass ACTI-Zeilen direkte Logik anstelle von invertierter Logik verwenden.
14181600cookie-checkWarum wird der ternäre Operator verwendet, um 1 und 0 in einem Makro zu definieren?yes
Nein, es gibt keinen Grund. Sie haben Recht.
– Kunst
31. März 2017 um 11:08 Uhr
Teilweise Off-Topic: Wann hört der Wahnsinn der Nutzung des Präprozessors auf? Hier liegt eine potentielle Mehrfachauswertung der beteiligten Funktionen vor. Einfach unnötig.
– Stefan
31. März 2017 um 13:29 Uhr
Manchmal ist es auch schön, explizit zu sein. Der ternäre Operator hier macht auf einen Blick deutlich, dass der Zweck des Makros darin besteht, einen booleschen Wert zurückzugeben.
– Rohr
31. März 2017 um 16:00 Uhr
Zumindest sollten die Makros verwendet werden
(alpha_char)
Anstatt vonalpha_char
nur damit es nicht kaputt geht wenn jemand etwas verrücktes versuchtATCI_IS_LOWER(true || -1)
.– Justin Time – Wiedereinsetzung von Monica
1. April 2017 um 21:27 Uhr
Sieht aus wie die Art von CI, die vor langer Zeit geschrieben wurde. Ich war von Pascal zu C gekommen, der eine dedizierte hatte
boolean
Typ, also verschwendete ich unzählige Zeit damit, Horror zu ändernif (n)
zuif (0 != n)
, wahrscheinlich fügt er eine zweifelhafte Besetzung hinzu, “um sicherzugehen”. Ich bin mir sicher, dass ich kugelsichere Ungleichungen magif (a < b) ...
, zu. Klar sah wie bei Pascalif a < b then ...
aber das wusste ich Cs<
war keinboolean
aber einint
und einint
könnte sein fast alles! Angst führt zu Vergoldung, Vergoldung führt zu Paranoia, Paranoia führt zu… solchem Code.– Kevin J. Chase
1. April 2017 um 22:06 Uhr