it-swarm.com.de

Warum wird der ternäre Operator zur Definition von 1 und in einem Makro verwendet?

Ich verwende ein SDK für ein eingebettetes Projekt. In diesem Quellcode habe ich einen Code gefunden, den ich zumindest eigenartig fand. In vielen Bereichen des SDK gibt es Quellcode in diesem Format:

#define ATCI_IS_LOWER( alpha_char )  ( ( (alpha_char >= ATCI_char_a) && (alpha_char <= ATCI_char_z) ) ? 1 : 0 )

#define ATCI_IS_UPPER( alpha_char )  ( ( (alpha_char >= ATCI_CHAR_A) && (alpha_char <= ATCI_CHAR_Z) ) ? 1 : 0 )

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 versuchte es mit zu bewerten

printf("%d", FOO == BAR);

und erhalten Sie das Ergebnis 1, so scheint es, dass sie gleich sind. Gibt es einen Grund, den Code so zu schreiben, wie er es getan hat?

79
Viktor S

Sie haben recht, in C ist es tautolog. Sowohl Ihre besondere ternäre Bedingung als auch (1 > 0) sind vom Typ int.

Aber in C++ wäre es wichtig , in einigen merkwürdigen Eckfällen (z. B. als Parameter für überladene Funktionen), da Ihr ternärer Bedingungsausdruck vom Typ int, während (1 > 0) ist vom Typ bool.

Ich vermute, dass der Autor einige Überlegungen angestellt hat, um die C++ - Kompatibilität zu erhalten.

132
Bathsheba

Es gibt Linting-Tools, die der Meinung sind, dass das Ergebnis eines Vergleichs boolesch ist und nicht direkt in der Arithmetik verwendet werden kann.

Namen nicht nennen oder Finger zeigen, aber PC-lint ist ein solches Flusenwerkzeug .

Ich sage nicht, dass sie recht haben, aber es ist eine mögliche Erklärung dafür, warum der Code so geschrieben wurde.

29
unwind

Sie werden dies manchmal in very old code sehen, bevor es einen C-Standard gab, aus dem (x > y) die Zahl 1 oder 0 auswertet; Einige CPUs würden stattdessen die Bewertung auf -1 oder 0 setzen, und einige sehr alte / Compiler sind vielleicht gerade gefolgt, so dass einige Programmierer der Meinung waren, dass sie die zusätzliche Verteidigung benötigen.

Sie werden dies manchmal auch sehen, weil ähnliche Ausdrücke nicht unbedingt auf die Zahl 1 oder 0 auswerten. Zum Beispiel in

#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) ? 1 : 0)

der innere &- Ausdruck ergibt entweder 0 oder den numerischen Wert von F_DO_GRENFELZ, der wahrscheinlich nicht 1 ist, daher dient der ? 1 : 0 zur Kanonisierung. Ich persönlich denke, dass es klarer ist, das als zu schreiben

#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) != 0)

aber vernünftige Menschen können nicht zustimmen. Wenn Sie einen ganzen Haufen davon in einer Reihe hatten und verschiedene Arten von Ausdrücken testeten, hätte jemand vielleicht entschieden, dass es pfleglicher ist, ? 1 : 0 am Ende von all von ihnen zu setzen, als sich darüber zu sorgen, welche tatsächlich benötigt werden es.

20
zwol

Es gibt einen Fehler im SDK-Code, und das Ternary war wahrscheinlich ein Fehler, um es zu beheben.

Als Makro können die Argumente (alpha_char) beliebige Ausdrücke sein und sollten in Klammern stehen, da Ausdrücke wie 'A' && 'c' den Test nicht bestehen.

#define IS_LOWER( x ) ( ( (x >= 'a') && (x <= 'z') ) ?  1 : 0 )
std::cout << IS_LOWER('A' && 'c');
**1**
std::cout << IS_LOWER('c' && 'A');
**0**

Aus diesem Grund sollten Makro-Argumente in der Erweiterung immer in Klammern gesetzt werden.

In Ihrem Beispiel (aber mit Parametern) sind beide abgehört.

#define FOO(x) (x > 0)
#define BAR(x) ((x > 0) ? 1 : 0)

Sie würden am besten durch ersetzt werden

#define BIM(x) ((x) > 0)

@CiaPan Der folgende Kommentar ist ein toller Punkt. Wenn ein Parameter mehr als einmal verwendet wird, führt dies zu undefinierbaren Ergebnissen. Zum Beispiel 

#define IS_LOWER( x ) (((x) >= 'a') && ((x) <= 'z'))
char ch = 'y';
std::cout << IS_LOWER(ch++);
**1** 
**BUT ch is now '{'**
16
Konchog

Eine einfache Erklärung ist, dass einige Leute entweder nicht verstehen, dass eine Bedingung denselben Wert in C zurückgibt, oder dass sie denken, dass es sauberer ist, ((a>b)?1:0) zu schreiben.

Das erklärt, warum einige ähnliche Konstrukte auch in Sprachen mit richtigen Booleschen verwenden, was in der C-Syntax (a>b)?true:false) wäre.

Dies erklärt auch, warum Sie dieses Makro nicht unnötig ändern sollten.

5
Hans Olsson

In C spielt es keine Rolle . Boolesche Ausdrücke in C haben den Typ int und einen Wert, der entweder 0 oder 1 lautet

ConditionalExpr ? 1 : 0

hat keine Wirkung.

In C++ ist dies eine Umwandlung in int, da bedingte Ausdrücke in C++ den Typ bool haben.

#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 dachte einfach, dass der Code klarer wurde.

5
PSkocik

Vielleicht gibt es als Embedded-Software einige Hinweise. Möglicherweise gibt es viele Makros, die mit diesem Stil geschrieben wurden, um einfach darauf hinzuweisen, dass ACTI-Leitungen direkte Logik anstelle von invertierter Logik verwenden. 

0
J.Guarin