int statt unsigned short - Wieso?
-
Hallo,
ich bin ja noch ein Newbe und folglich lese ich sehr viel um C++ ordentlich zu lernen. Unter anderem ist mir das Buch "Bjarne Stroustrup: Die C++ Programmiersprache (Deutsche Übersetzung der Special Edition). Addison-Wesley 2000, ISBN 382731660X" empfohlen worden, welches ich gerade durcharbeite. Abenso schaue ich antürlich viele Tuts an um viel zu lernen und teste viel.
Eine Sach fällt mir immer mehr auf, die zwar so sein mag, mir sich aber der Grund nicht ganz erschließt.
bool f(int i) { if ((i<0) || (i>10)) return false; return true; }Wieso soll ich ein int benutzen, wenn ein unsigned short doch hier wohl die bessere Wahl wäre? Auch Bjarne schreibt in seinen Ratschlägen "Bevorzuge ein int anstatt einen bz. unsigned short oder long" (kein Zitat, sondern Sinngemäß, weil Buch gerade nicht zur Hand).
Kann mir das jemand erklären. Ein unsigned short ist doch eindeutig, dass die Zahl nicht kleiner 0 sein kann, also macht es doch mehr Sinn erst keine negativen Zahlen zuzulassen. Und short ist sicherlich immer im Bereich bis 10, selbst auf den kleinsten Bit-Systemen. Was ist also am int so toll, dass man nicht seine Verwandten nehmen soll, besonders bei einem so einfachen Beispiel wie oben?
Bitte um Aufklärung,
Danke,
Stefan
-
stefanjann schrieb:
Eine Sach fällt mir immer mehr auf, die zwar so sein mag, mir sich aber der Grund nicht ganz erschließt...
Wieso soll ich ein int benutzen, wenn ein unsigned short doch hier wohl die bessere Wahl wäre? Auch Bjarne schreibt in seinen Ratschlägen "Bevorzuge ein int anstatt einen bz. unsigned short oder long" (kein Zitat, sondern Sinngemäß, weil Buch gerade nicht zur Hand).
int entspricht in der Regel dem Typ, mit dem der Rechner arbeitet (z.b. häufig 32 Bit auf ein 32 Bit-System und 64 bit auf einem 64-Bit System). Dies kann (muss aber nicht) gewisse Performancevorteile etc. mit sich bringen.
Ich bin aber auch eher der Fan davon die Typen zu verwenden die ich für den Fall am sinnvollsten halte.
cu André
-
Ein USHORT (unsigned short) hat in dem oben genanten Beispiel natürlich bessere Verwendung, ein char (mit Umwandlung, sodass er nicht als Buchstabe angesehen wird) noch mehr, aber ich vermute, dass die Aussage des Autors ein Allgeimplätzchen ist, das du dann verwenden solltest, wenn du nicht sicher bist. Typenwirrköpfe hat es schon immer gegeben, auch bei Microsoft.
Aus der MFC (oder so ähnlich):
#define TRUE 1 #define FALSE 0 typedef int BOOL; // Vier Byte für einen Wahrheitswert!Wie du siehst, definiert Microsoft in eigenen Klassenbibliotheken einen eigenen boolischen Typen, der vier statt 1 Byte Speicher verbraucht. Selbst wenn man bedenkt, dass es in C (nicht C++) keinen Typ bool gibt und Microsoft auch C-Programmierer unterstützen wollte, muss man sich fragen, warum sie kein BYTE (unsigned char, 1 Byte) genommen haben.
-
Manchmal nimmt man sie für qualifizierte Fehlermeldungen.
bool f(int i) { if (i<0) throw LogigError("Du bist ein Weihnachtsmann!"); if (i>10)) throw LogigError("Du bist ein Osterhase!"); return true; }
-
Der aus dem Westen... schrieb:
ein char (mit Umwandlung, sodass er nicht als Buchstabe angesehen wird) noch mehr,
Ein char brauchst du auch nicht umwandeln, das ist ja schon ein numerischer Typ. Und selbst wenn, in was würdest du ihn denn dann konvertieren? In ein int?

-
Kann es evtl. auch daran liegen, dass der Compiler von Haus aus bei Zahlen von einem int ausgeht?
main { f(5); // 5 ist int? }
-
stefanjann schrieb:
Kann es evtl. auch daran liegen, dass der Compiler von Haus aus bei Zahlen von einem int ausgeht?
Das gilt, solange du die Zahlen nicht speziell angibst (5ul bedeutet z.B. eine 5 [unsigned long]).
-
Mein Compiler hat sowieso einen an der Waffel. Entweder macht er nicht das, was ich will, oder er macht alles doppelt und dreifach. Sobald ich aber die MFC einbinde, läuft er sogar ganz gut. Komisch, nicht...
Ja, es gibt nämlich Standartkonvertierungen.
IrgendeineFunktion("Irgendein String"); // Typ ist char* IrgendeineFunktion((BYTE*)"Irgendein String"); // Typ ist BYTE* IrgendeineFunktion(L"Irgendein String"); // Type ist wchar_t* IrgendeineFunktion(1); // Typ ist int IrgendeineFunktion((unsigned)1); // Typ ist unsigned int IrgendeineFunktion((USHORT)1); // Typ ist USHORTNur wenn man dem Compiler ganz genau sagt, wie er den Wert behandeln soll, gibt es keine Konvertierung.
-
Der aus dem Westen... schrieb:
Ja, es gibt nämlich Standartkonvertierungen.
...
Nur wenn man dem Compiler ganz genau sagt, wie er den Wert behandeln soll, gibt es keine Konvertierung.
Doch, genau das machst du hier: Konvertieren (Teilweise unnötig, und zudem solltes du lieber wenn du konvertierst auf die C++ Casts zurückgreifen - sind sicherer). Wenn du Zahlen von haus aus richtig angibst (wie in meinen Beispiel 5ul für eine 5 [unsigned long]) gibt es keine Konvertierung zur Laufzeit mehr.
-
asc schrieb:
Doch, genau das machst du hier: Konvertieren (Teilweise unnötig, und zudem solltes du lieber wenn du konvertierst auf die C++ Casts zurückgreifen - sind sicherer).
Bockmist!
foo(static_cast<char>(5)); ist nicht sicherer als foo(char(5)); oder foo((char)5);asc schrieb:
Wenn du Zahlen von haus aus richtig angibst (wie in meinen Beispiel 5ul für eine 5 [unsigned long]) gibt es keine Konvertierung zur Laufzeit mehr.
Genau so klug wie die erste These.
foo((unsigned long)5); erzeugt keine Konvertierung zur Laufzeit.
-
volkard schrieb:
Bockmist!
foo(static_cast<char>(5)); ist nicht sicherer als foo(char(5)); oder foo((char)5);
-
volkard schrieb:
asc schrieb:
Doch, genau das machst du hier: Konvertieren (Teilweise unnötig, und zudem solltes du lieber wenn du konvertierst auf die C++ Casts zurückgreifen - sind sicherer).
Bockmist!
foo(static_cast<char>(5)); ist nicht sicherer als foo(char(5)); oder foo((char)5);Aber dies:
IrgendeineFunktion((BYTE*)"Irgendein String");
empfinde ich als Sicherheitsrisiko - wenn man sich nicht darauf verlässt das BYTE* gleich char* ist. Da sehe ich lieber wenn eine reinterpretierung statt findet.IrgendeineFunktion(reinterpret_cast<BYTE*>("Irgendein String"));volkard schrieb:
Genau so klug wie die erste These.
foo((unsigned long)5); erzeugt keine Konvertierung zur Laufzeit.Gut, wusste noch nicht das die C-Casts standardmäßig vom Compiler rausoptimiert werden. Weil die 5 hier erst einmal ein int-Wert ist, eine 5ul wäre ein unsigned long.
-
asc schrieb:
Aber dies:
IrgendeineFunktion((BYTE*)"Irgendein String");
empfinde ich als Sicherheitsrisiko - wenn man sich nicht darauf verlässt das BYTE* gleich char* ist. Da sehe ich lieber wenn eine reinterpretierung statt findet.Ich auch.
Aber wenn man dogmatisch alles mit <>-casts macht, wie Du es vorschlägst, schwächst Du die erwünsche Signalwirkung desreinterpret_castdoch nur ab.
-
_matze schrieb:
volkard schrieb:
Bockmist!
foo(static_cast<char>(5)); ist nicht sicherer als foo(char(5)); oder foo((char)5);
Auch:

-
Zurück zum Thema:
void book(int page) // oder unsigned short? { switch (page) { case 1: cout << .... break; case 2: cout << .... break; case 3: cout << .... break; default: cout << "Seite nicht vorhanden\n"; } } int main() { book(1); book(3); }Was macht jetzt mehr Sinn? int oder unsigned short. Wenn ich euch richtig verstanden habe, dann eigentlich unsigned short, weil ich mir sicher bin, dass es ja keine negativen Zahlen geben wird und der Wertebereich sicherlich abgedeckt ist. Könnte ich diese Dinge nicht sicher stellen, dann int. Richtig verstanden?
-
Nimm int. damit ist alles am einfachsten. Unsigned nur, wenn negtive Zahlen stören würden
-
Du vergisst aber asc's Post:
asc schrieb:
int entspricht in der Regel dem Typ, mit dem der Rechner arbeitet (z.b. häufig 32 Bit auf ein 32 Bit-System und 64 bit auf einem 64-Bit System). Dies kann (muss aber nicht) gewisse Performancevorteile etc. mit sich bringen.
Kann natürlich nur irgendwie merkliche Vorteile bringen, wenn man sich in rechenintensiven Routinen befindet (wenn überhaupt). Im Beispiel isses sowieso Pott wie Deckel. Es sei denn, du willst unbedingt die 2 Bytes sparen. Und Signed oder Unsigned ist im Beispiel doch auch egal. Im Speicher ist es dasselbe. Solange du nicht <>-Vergleiche machst oder so, macht's doch keinen Unterschied. Es kann aber quasi zur "Dokumentation" im Code beitragen. Wenn eine Funktion ein unsigned int verlangt, kommst du gar nicht erst auf die Idee, was Negatives zu übergeben.
-
volkard schrieb:
Aber wenn man dogmatisch alles mit <>-casts macht, wie Du es vorschlägst, schwächst Du die erwünsche Signalwirkung des
reinterpret_castdoch nur ab.Das "Aber wenn man dogmatisch alles mit <>-casts macht, wie Du es vorschlägst" habe ich niemals gesagt, sondern nur das ich statt C-Casts immer die C++ Pendants verwenden würde (Da ich danach auch suchen kann, bei C-Casts ist dies nicht eindeutig möglich).
Ich würde an den meisten Stellen keinen Cast verwenden, wenn ich dies durch eine explizite Typangabe eh umgehen kann. Ich verwende statt "static_cast<unsigned long>(5)", "(unsigned long)5" oder "unsigned long(5)" einfach gleich die typisierte 5 ("5ul").
-
asc schrieb:
oder "unsigned long(5)"
Das geht ja genausowenig wie
int*(0)für einen Nullzeiger auf int.
Es muss schon ein Wort sein. Sonst benutz ich aber auch mal gern die Funktions-Syntax für's statische Casting.Gruß,
SP
-
asc schrieb:
Das "Aber wenn man dogmatisch alles mit <>-casts macht, wie Du es vorschlägst" habe ich niemals gesagt, sondern nur das ich statt C-Casts immer die C++ Pendants verwenden würde (Da ich danach auch suchen kann, bei C-Casts ist dies nicht eindeutig möglich).
Du nimmst möglichst immer die <>-casts. Aus prinzipiellen Gründen. Unabhängig vom Umfeld. Das ist doch Dogmatismus pur. Daß Du das innerhalb eines Satzes abstreitest und dann doch belegst, beleidigt meine Intelligenz.[/quote]
Ich würde an den meisten Stellen keinen Cast verwenden, wenn ich dies durch eine explizite Typangabe eh umgehen kann. Ich verwende statt "static_cast<unsigned long>(5)", "(unsigned long)5" oder "unsigned long(5)" einfach gleich die typisierte 5 ("5ul").
Ich sehe, daß Du noch nicht auf die einschlägigen Probleme damit gestoßen bist. Ich leuchte mal voraus:
bool isprime(u16 n);//lookup and wheel bool isprime(u32 n);//additional SPRP bool isprime(u64 n);//more SPRP, result truth depending on riemann hypothesis ... cout<<isprime(u16(100));Welche typsuffixe nimmt man eigentlich für einen 16-bittigen unsigned int? welchen suffix für size_t?
-
asc schrieb:
volkard schrieb:
asc schrieb:
Doch, genau das machst du hier: Konvertieren (Teilweise unnötig, und zudem solltes du lieber wenn du konvertierst auf die C++ Casts zurückgreifen - sind sicherer).
Bockmist!
foo(static_cast<char>(5)); ist nicht sicherer als foo(char(5)); oder foo((char)5);Aber dies:
IrgendeineFunktion((BYTE*)"Irgendein String");
empfinde ich als Sicherheitsrisiko - wenn man sich nicht darauf verlässt das BYTE* gleich char* ist. Da sehe ich lieber wenn eine reinterpretierung statt findet.IrgendeineFunktion(reinterpret_cast<BYTE*>("Irgendein String"));Da hätte ich jetzt irgendwie anders argumentiert:
IrgendeineFunktion(static_cast<BYTE*>("Irgendein String"));Gibt einen Fehler, falls es unterschiedliche Zeiger sind. Daher eben auch sicherer.
@volkard,
Benutzt du eigentlich C++ Casts oder verfolgst du den Dogmatismus "Alles nur mit C Cast"? Wenn du C++ Casts verwendest: wann, wo und wieso?
Würde mich jetzt mal interessieren.Grüssli