Hallo, verwende den freien Compiler XC32 von Microchip. Habe jetzt festgestellt, das ein "bool" die gleich Größe an Ram Speicher wie ein "char" verbraucht. Warum sollten man dann überhaupt "bool" verwenden ? Warum bekommt es ein moderner Compiler nicht hin, in ein Byte 8 bools zu packen ?????
:
Bearbeitet durch User
Dirk F. schrieb: > Warum bekommt es ein moderner Compiler nicht hin, in ein Byte 8 bools zu > packen ????? Warum sollte man das wollen? Den allermeisten sind die 8bits egal, die wollen Geschwindigkeit. Nur ein paar exotische Mikrocontroller-Nerds fahren auf solche Bitfrickeleien ab. Oliver
Ineffizient. Ein Byte oder ein Wort lesen, dann die anderen Bits ausmaskieren kostet Zeit und Code. Beim Schreiben genauso. Ausnahme: Der Prozessor hat entsprechende Bit-Befehle, etwa MSC-51 oder bei ARM Bitbanding. Letzteres wird aber nur stiefmütterlich unterstützt und ist (deshalb?) bei neueren Typen gar nicht mehr vorhanden.
Dirk F. schrieb: > peicher wie ein "char" verbraucht. Ja klar, was denn sonst? Speicherzellen sind numal mindestens 8 bit groß. Dirk F. schrieb: > Warum sollten man dann überhaupt "bool" verwenden ? Warum sollte ich mich mit CHAR mit 255 Zuständen herumschlagen, wenn bool schon vom Compiler aus nur zwei Zustände kennt? Dirk F. schrieb: > Warum bekommt es ein moderner Compiler nicht hin, in ein Byte 8 bools zu > packen ????? Wieviel Speicher denkst Du denn, kostet es, sich zu merken, wo und an welcher Stelle der Bool ist?
Dirk F. schrieb: > Warum sollten man dann überhaupt "bool" verwenden ? Das dachten sich Kernigham&Ritchi auch. > Warum bekommt es ein moderner Compiler nicht hin, in ein Byte 8 bools zu > packen ???? Sie bekommen es hin, alles eine Frage wie gut der Compilerschreiberling war. https://onlinedocs.microchip.com/oxy/GUID-BB433107-FD4E-4D28-BB58-9D4A58955B1A-en-US-5/GUID-1D1337FF-1B2E-4E4A-BDF3-31254932C478.html Entscheidend ist, pointer auf Bits zu verbieten, damit
1 | *register.bit3 |
kein Problem wird.
:
Bearbeitet durch User
Andreas B. schrieb: > Ineffizient. Jo! Einfach sich mal eine Makro bastel was sowas nachbildet und sich dann den Assembler output anschauen. Um 7-Bit Datenspeicher einzusparen, hat man dafür dann mehrere Byte an zusätzlichem Code bei jedem Zugriff darauf. Im Prizip kann man sich sowas auch mit "bit field" nachbasteln, da erzeugt der Compiler dann den ganzen zusätzlichen Programmcode im Hintergrund: - https://en.cppreference.com/w/c/language/bit_field
Irgend W. schrieb: > Um 7-Bit Datenspeicher einzusparen, hat man dafür dann mehrere Byte an > zusätzlichem Code bei jedem Zugriff darauf. Nicht unbedingt, wie uC haben Bitadressierungszugriffsarten, da ist das 1 Befehl. Ob der Compiler sie effizient nutzt, wie ein Assemblerprogrammierer, sei dahingestellt, viele Compiler sind strohfoof.
Dirk F. schrieb: > Warum bekommt es ein moderner Compiler nicht hin, in ein Byte 8 bools zu > packen ????? Tut er doch! ... Wenn möglich und GEWÜNSCHT. Also auf die Optimierungsstufe achten! (Standard für lau tut/tat!) (Zuletzt mit V5.x verwendet und geprüft. Nich weils nötig war, nur haben wollen, mus so sein etc. :)
Teo D. schrieb: > Zuletzt mit V5.x verwendet Von welchem Compiler redest Du ? Ich: XC32 Version 4.35
Dirk F. schrieb: > Von welchem Compiler redest Du ? > > Ich: XC32 Version 4.35 Ubs, völlig verplant... Das war die IDE Version. :} XC8 2,36 Ja, andere Baustelle aber ich könnt mein linken Schuh drauf verwetten... Wenn ich mich recht erinnere, hab ich die alle als Global anlegen müssen(?) und das Progrämmchen war wirklich mehr überschaubar.
Teo D. schrieb: > Dirk F. schrieb: >> Warum bekommt es ein moderner Compiler nicht hin, in ein Byte 8 bools zu >> packen ????? > > Tut er doch! ... Wenn möglich und GEWÜNSCHT. > Also auf die Optimierungsstufe achten! (Standard für lau tut/tat!) > (Zuletzt mit V5.x verwendet und geprüft. Nich weils nötig war, nur haben > wollen, mus so sein etc. :) Ist das Chinesisch? Lau tut tat? Bitte uebersetze doch Mal.
Joe schrieb: > Lau tut tat? "für lau" == umsonst (aber nicht vergebens), "für umme", kostenfrei, gratis tut = macht etwas jetzt, Gegenwart tat = machte etwass früher mal, Vergangenheit
Harald K. schrieb: > tat = machte etwass früher mal, Vergangenheit Tat = Schreibfehler -> Dat = Das/Dieses :DDD
Teo D. schrieb: > Tat = Schreibfehler Klingt in diesem Kontext dann aber komplett bizarr: > Also auf die Optimierungsstufe achten! (Standard für lau tut/tat!) > (Zuletzt mit V5.x verwendet und geprüft. Ich hatte mir das so ins Hochdeutsche übersetzt: Also auf die Optimierungsstufe achten, die [im XC8] kostenlose Standardoptimierung genügt bzw. genügte früher, als ich [Teo] das mit V5.x [des XC8] nutzte. --- Oh, meine Fehlschreibung "etwass" ist peinlich, da muss die Tastatur geprelllllllllt und ich Blindfisch das nicht gesehen haben.
Also: * Pointer * Maskierung * Race Conditions * Shift-Aufwand (Zuweisung) Wobei der fehlende Ptr viele weitere Dinge impliziert, z.b. Ansicht im Debugger, Arraxs, memcpy, sizeof...
> Warum sollten man dann überhaupt "bool" verwenden ?
Damit man quasi "natursprachlichen" Code niederschreiben kann.
OK, für einen englisch-sprecher ist der Verständnisvorteil
offensichtlicher:
1 | if (motorenabled) led_red = 0xFF; //statt |
2 | |
3 | |
4 | if (motorenabled != 0) led_red = 0xFF; // oder |
5 | |
6 | |
7 | if (motorenabled == 0xFF) led_red = 0xFF; |
mit dem Schlüsselwort "then" wäre es noch "natürlicher" Auf deutsch und auf "magic numbers" verzichtet:
1 | falls motorangeschaltet dann Rotlicht = VOLL; |
aber wer lässt sich schon c-code "vorlesen" oder legt Wert darauf, das auch C-Unkundige verstehen könnten was das Programmieräffchen da zusammengekritzelt hat hat...
Klaus K. schrieb: > if (motorenabled) led_red = 0xFF; //statt > > if (motorenabled != 0) led_red = 0xFF; Dafür braucht man keine Bools, if(motorenabled) würde auch mit einem int o.dgl. funktionieren. Klaus K. schrieb: > Programmieräffchen Der obige Griff ins Klo macht diese Äusserung noch peinlicher.
Hmmm schrieb: > Dafür braucht man keine Bools, if(motorenabled) würde auch mit einem int > o.dgl. funktionieren. Klar, damit geht dann auch motorenabled ++ Wer weiß, vielleicht möchte man ja mal mitteilen, der Motor sei "doppelt plus an". Schönen Gruß an Herrn Blair!
Hmmm schrieb: > Dafür braucht man keine Bools, if(motorenabled) würde auch mit einem int > o.dgl. funktionieren. > ... Es geht natürlich beides. Mit bool kann man in C nicht mehr machen als auch mit int oder char möglich ist. Aber mit bool drückt man klar aus, daß man nicht mit einer von vielen möglichen Zahlen hantieren will, sondern mit "ja" oder "nein". (Es soll Leute geben, die lesbare Programme bevorzugen.) In C++ wird es dann interessanter, weil da mehr auf Typen geachtet wird. Bspw. beim Überladen von Funktionen kann ein Aufruf mit einer bool etwas anderes sein als ein Aufruf mit einer Zahl. Man könnte eine Funktion, die Werte ausgibt, z.B. für bool anders überladen als für char oder int:
1 | bool b = false; |
2 | char c = 'A'; |
3 | int i = 42; |
4 | ...
|
5 | print( b ); // könnte "false" ausgeben oder "no" statt 0 |
6 | print( c ); // könnte A ausgeben statt 65 |
7 | print( i ); // könnte 42 ausgeben |
Oder streams (vulgo files, wie std::cout als Standardausgabe, oder eine echte Datei): Wenn man so einen stream an etwas übergibt, was einen stream erwartet, wird er halt als stream behandelt. f.write(...) würde also etwas in die Datei f schreiben, und wieder f zurückliefern. Benutzt man einen stream aber in einem logischen Ausdruck, wird er in bool konvertiert. Diese Konvertierung ist für streams aber so überladen, daß sie true ergibt, wenn der stream noch funktioniert, oder false, wenn nicht (z.B. Fehler aufgetreten). Das ermöglicht eine Konstruktion wie:
1 | while( f.read(...) ) tuwas... |
, weil while einen logischen Ausdruck braucht und die Konvertierung von f nach bool den Status des streams liefert. Wer also meint, bool ist überflüssig, der hat eigentlich recht und darf gerne ohne bool weiter herumstümpern :-)
Ich denke, dass bool beim C99 Standard extra für die Pascal und Basic - Koryphäen eingeführt wurde, weil die damals auch mal C probieren wollten!
Auch Nichtkoryphäen, haben da gerne mit Defines, ihre Programme aufgehübscht. Wurde grad von XC8 (2.36) enttäuscht. Hab mal auf die schnelle, einer Funktion mit Booleschen Rückgabewert, ne Zahl >1 zugewiesen. Nich mal ne Warnung (-9) gibts. :´(
Teo D. schrieb: > Wurde grad von XC8 (2.36) enttäuscht. Ich meine beim XC8 Compiler gibt es doch den Datentyp "bit" Den vermisse ich beim XC32.....
Harald K. schrieb: > Oh, meine Fehlschreibung "etwass" ist peinlich, da muss die Tastatur > geprelllllllllt und ich Blindfisch das nicht gesehen haben. Maddonix iddonetlimm! (Macht fast gar nichts, ist wirklich nicht so schlimm)
Teo D. schrieb: > ne Zahl >1 zugewiesen. Nich mal ne Warnung (-9) gibts Ist ja eigentlich auch nicht schlimm: * Mit 1/true/!0/!false vergleicht man eh nicht * Warnungen macht Lint oder Co Auf die Schnauze fällt man dann, wenn man es einem bitfeld-bool zuweist. (Seit einiger Zeit nutze ich 0/1 statt false/true. Keine Ahnung, warum ich das geringfügig besser lesbar finde, trotz verwechselungsgefahr mit integerwert)
Bruno V. schrieb: > Teo D. schrieb: >> ne Zahl >1 zugewiesen. Nich mal ne Warnung (-9) gibts > > Ist ja eigentlich auch nicht schlimm: Aber ne Warnung wärs wert, denke ich. Ich glaub, ein paar Synapsen tuns grad wieder... Wenn ich mich recht erinnere, ist beim XC8 bool, auch nur ein Makro mit _bit. Das in ein Byte stopfen, geht denke ich, da auch nur mit statischen.
Wladimir schrieb: > Ich denke, dass bool beim C99 Standard extra für die Pascal und Basic - > Koryphäen eingeführt wurde, weil die damals auch mal C probieren > wollten! bool in Basic ? Hatte der 9kbyte grosse Interpreter des C64 überhaupt Platz für solchen Zuckerguß? https://www.c64-wiki.de/wiki/C64-Befehle Und klar, das "boolean" als Hochsprachenkonstrukt von Embedded Hackern die C eher als eine Art "Assembler für Warmduscher" verwenden, weitgehend ignoriert wird. Dabei kann man mit passender Typisierung viele Fehler vermeiden bzw. schon im Compiler abfangen. Es sind schon Raketen abgestürzt wegen dem falschen typ.
Klaus K. schrieb: > Wladimir schrieb: >> Ich denke, dass bool beim C99 Standard extra für die Pascal und Basic - >> Koryphäen eingeführt wurde, weil die damals auch mal C probieren >> wollten! > > bool in Basic ? Hatte der 9kbyte grosse Interpreter des C64 überhaupt > Platz für solchen Zuckerguß? 1999 ist für den C64 etwas spät. Das war 5 Jahre nach EOL. Es war eher so die Zeit, als sie alle mit Visual Basic hantiert haben, das es da schon seit 8 Jahren gab.
:
Bearbeitet durch User
> 1999 ist für den C64 etwas spät. Das war 5 Jahre nach EOL. Es war eher > so die Zeit, als sie alle mit Visual Basic hantiert haben, das es da > schon seit 8 Jahren gab. Naja, wenn man "Visual Basic" meint sollte man auch "visual Basic" schreiben und nicht "BASIC". Und bei den amüsanten Vergleich zwischen C99 und "dem Rest der welt" geht es wohl eher um die Unterscheidung in "stark" und "Schwach" typisierte Sprachen. https://de.wikipedia.org/wiki/Typisierung_(Informatik)#Beispiele Und das alle mit Visual Basic hantiert hätten ... IMHO gab es da mehr als das sprichwörtliche Gallische Dorf die ihren eigenen Zaubertrabk köchelten und damit in die Schlacht zogen: (Borland-) Pascal, ADA, Modula-2, Lisp, Forth, Erlang, .... Wobei ohne Betrachtung des Anwendungsgebietes ist diese Einteilung IMHO allein zweckfrei. Esy geht halt darum, ob man in konkreten Anwendung Vorteile durch die Verwendung von "passenden Typen" hat. Der Prozessor selbt hat hat nur die Typen Datenbusbreite (char, int) und pointer auf Speicherzelle an Datenbus. Damit kommt dann auch der Embedded Coder besten aus. Und dann gibt es Applikationen, die abstrakt weit weg vom Prozessor sind, beispielsweise GUI oder natursprachlich formulierte Ablaufsteuerungen, Datenbanken, ... die sind dann eher für "Hochsprachen und ihre Concepte" geeignet, da möchte man nicht die Programmlogik durch Maschinendetails "verbogen" sehen.
Klaus K. schrieb: > Naja, wenn man "Visual Basic" meint sollte man auch "visual Basic" > schreiben und nicht "BASIC". Da stand "Basic", nicht "BASIC", und da das BASIC vom C64 zu der Zeit keine Rolle mehr gespielt hat und wie du richtig angemerkt hast, auch keinen bool-Typ hat, war das offensichtlich nicht gemeint. > Und bei den amüsanten Vergleich zwischen C99 und "dem Rest der welt" geht > es wohl eher um die Unterscheidung in "stark" und "Schwach" typisierte > Sprachen. > https://de.wikipedia.org/wiki/Typisierung_(Informatik)#Beispiele Es ging um die Frage, warum C99 einen Typ bool eingeführt hat. Das hat erst mal nicht soviel damit zu tun, dass C schwach typisiert ist. Es ist eher so, dass es deswegen nicht zwingend ein bool gebraucht hat und daher anfangs keins hatte. Schließlich funktioniert ja z.B. in einem if auch ein beliebiger numerischer oder Zeiger-Typ als Bedingung. > Und das alle mit Visual Basic hantiert hätten ... IMHO gab es da mehr > als das sprichwörtliche Gallische Dorf die ihren eigenen Zaubertrabk > köchelten und damit in die Schlacht zogen: (Borland-) Pascal, ADA, > Modula-2, Lisp, Forth, Erlang, .... Mit "alle" meinte ich alle, die irgendwas mit Basic am Hut haben, nicht alle Programmierer weltweit. C64-BASIC war 1999 nicht mehr so gefragt. > Wobei ohne Betrachtung des Anwendungsgebietes ist diese Einteilung IMHO > allein zweckfrei. Esy geht halt darum, ob man in konkreten Anwendung > Vorteile durch die Verwendung von "passenden Typen" hat. Ja, deshalb hat man ja Hochsprachen. > Und dann gibt es Applikationen, die abstrakt weit weg vom Prozessor > sind, beispielsweise GUI oder natursprachlich formulierte > Ablaufsteuerungen, Datenbanken, ... die sind dann eher für > "Hochsprachen und ihre Concepte" geeignet, da möchte man nicht die > Programmlogik durch Maschinendetails "verbogen" sehen. Wobei es natürlich trotzdem meist gewisse Randbedingungen gibt.
Dirk F. schrieb: > Warum sollten man dann überhaupt "bool" verwenden ? Damit man Hochsprachencode mit "true" und "false". schreiben kann. Mir fällt es aber trotzdem leichter, logische Operationen z.B. in Bitfeldern zu verarbeiten. Von Flags, logischen Operationen mit Registern, um diese zu setzen, und lustigem Hin- und Herspringen willst du lieber nichts wissen.. ;) Abfragen wie or ax,ax gleich an den Anfang einer (bestimmten) Schleife zu setzen, hatte mir mal ein professioneller Programmierer beigebracht. Der Code von dem sah im Debugger auch super aus. Aber der konnte auch gut coden. Von der Performance her sind auch Algorithmen sehr beliebt, wie auch effektiv.
:
Bearbeitet durch User
Beitrag #7555481 wurde vom Autor gelöscht.
Irgendwie übersehen hier alle, dass ein C99 bool die tolle Eigenschaft hat, dass er immer 0 oder 1 ist. Man braucht auch beim Casten von größeren Datentypen keine Angst zu haben, dass nur die unteren Bits beachtet werden. 0x40000 in einen bool mit sizeof(bool) == 1 zu casten, liefert 1. Das gleiche in einen uint8_t zu casten, liefert 0.
Daniel G. schrieb: > Irgendwie übersehen hier alle, dass ein C99 bool die tolle Eigenschaft > hat, dass er immer 0 oder 1 ist. Man braucht auch beim Casten von > größeren Datentypen keine Angst zu haben, dass nur die unteren Bits > beachtet werden. 0x40000 in einen bool mit sizeof(bool) == 1 zu casten, > liefert 1. Das gleiche in einen uint8_t zu casten, liefert 0. Tja, wer zu doof zum casten ist, sollte es lassen.
1 | uint8_t KleinerDatentyp = GrosserDatentyp ? 1 : 0; |
:
Bearbeitet durch User
Tim T. schrieb: > Tja, wer zu doof zum casten ist, sollte es lassen. Der übliche kurze Hack ist !! (Bei einem Argument, sonst && oder ||) Es ist aber super, wenn man gar keinen Hack braucht.
Rbx schrieb: > Abfragen wie or ax,ax gleich an den Anfang einer (bestimmten) Schleife Hast Du mal ein Beispiel? Oder geht es nur um Assembler-Hacks
Daniel G. schrieb: > Irgendwie übersehen hier alle, dass ein C99 bool die tolle Eigenschaft > hat, dass er immer 0 oder 1 ist. Man braucht auch beim Casten von > größeren Datentypen keine Angst zu haben, dass nur die unteren Bits > beachtet werden. Ein boolean wird nie gecastet, ein boolean wird nur in Bedingungsoperatoren wie if () etc verarbeitet. Siehe auch Beitrag "Re: Welchen Sinn hat der Datentyp "bool"?" und Matthäus 5,37 .
Klaus W. schrieb: > Benutzt man einen stream aber in einem logischen Ausdruck, wird er in > bool konvertiert. Wobei es in C++98 ulkigerweise noch void* statt bool war. Und dieser war dann je nach Stream-Status ein Nullpointer oder nicht.
Beitrag #7556325 wurde vom Autor gelöscht.
Bruno V. schrieb: > Hast Du mal ein Beispiel? Oder geht es nur um Assembler-Hacks Es geht nur um eine Bedingungsprüfung. Du könntest auch IF(ax) schreiben. In Asm geht aber die Schleifenkonstruktion etwas anders als in C, und Asm-Schleifen sind auch nicht so stark standardisiert. Beim Intel gibt es aber Befehlserleichterungen wie loop oder repz und auch die Register wie SI und DI z.B. für Richtungsabarbeitungen. Mit "Hacks" hat das nichts zu tun. Mit in logischen Operationen gut sein, aber schon.
Rbx schrieb: > In Asm geht aber die Schleifenkonstruktion etwas anders als in C M.E. doch Assembler-Hacks. Z.B. XOR zum löschen eines Registers oder swap Zweier. Also was als Pattern für seinen Assembler lernt und der C-Compiler auch kennt.
>> Warum sollten man dann überhaupt "bool" verwenden ? > > Warum sollte ich mich mit CHAR mit 255 Zuständen herumschlagen, wenn > bool schon vom Compiler aus nur zwei Zustände kennt? Jo, genau - hilft zur Vermeidung von Seiteneffekten bei z.B. Rückgabewerten. Angenommen musst nen Test schreiben, und musst potentiell alle Restklassen eines chars durchklappern, weil jemand auf Platz optimiert hat. Kann zwar auch sinnvoll sein, kommt aber drauf an. Pauschal da nur 2 Zustände brauchen zu müssen, könnte man halt irgendwie dezent als etwas sauberer erachten.
ich hätte ja nichts dagegen, wenn ein bool auch tatsächlich ein bool wäre. Ich habe aber noch keinen (C-) Compiler gesehen, der bei
1 | static bool b = 12; |
einen Fehler oder auch nur eine Warnung ausgespuckt hätte. So ist das keine Spur besser als
1 | #define bool int |
Markus F. schrieb: > Ich habe aber noch keinen (C-) Compiler gesehen, der bei > static bool b = 12; > einen Fehler oder auch nur eine Warnung ausgespuckt hätte. Selbst bei den C++ Compilern warnt nur MSVC, die anderen nur bei
1 | static bool b {12}; |
Oliver
:
Bearbeitet durch User
Markus F. schrieb: > ich hätte ja nichts dagegen, wenn ein bool auch tatsächlich ein bool > wäre. Ein bool ist ein bool ist ein bool. > Ich habe aber noch keinen (C-) Compiler gesehen, der bei > static bool b = 12; > einen Fehler oder auch nur eine Warnung ausgespuckt hätte. Das liegt aber nicht daran, dass es kein bool wäre, sondern daran, dass ein int implizit nach bool konvertiert werden kann. In b steht nachher nämlich trotzdem keine 12 drin. > So ist das keine Spur besser als > #define bool int Doch, denn da stünde nachher 12 drin.
Codevision AVR kann mit bool umgehen und macht die auch wirklich nur ein bit breit in einem Register.
Markus F. schrieb: > Ich habe aber noch keinen (C-) Compiler gesehen, der bei static bool b = > 12; > einen Fehler oder auch nur eine Warnung ausgespuckt hätte. So ist das > keine Spur besser als #define bool int Nö, da ist ein großer Unterschied. C macht eine automatische Konvertierung auf den Zieltyp ohne Warnung. Aus 12 wird also b = true d.h. b = 1.
:
Bearbeitet durch User
Rainer W. schrieb: > b=12 ist auch true Das ist missverständlich: Alles != 0 (also auch 12) wird zu true gewandelt, wenn eine boolsche Entscheidung gebraucht wird (z.B. bei if, while, ...). if(b==true) ist hingegen nur erfüllt, wenn b ein bool ist, nicht wenn es ein int ist. Bei if & Co behilft man sich, indem man niemals auf true vergleicht (was den code oft besser macht). Bei Zuweisungen erfordert es jedoch Klimmzüge:
1 | int myBool_b = 256; |
2 | uint8_t myBool_c = b; /* geht schief */ |
3 | uint8_t myBool_d = !!b; /* Klimmzug */ |
Rainer W. schrieb: > Peter D. schrieb: >> Aus 12 wird also b = true d.h. b = 1. > > b=12 ist auch true b=12 geht aber eben nicht, weil b ein bool ist, der den Wert 12 nicht annehmen kann.
Rolf M. schrieb: > b=12 geht aber eben nicht, weil b ein bool ist, der den Wert 12 nicht > annehmen kann. Wie ist das vorgegeben? Meckert der compiler dann, oder macht er einfach still ein TRUE (1) aus der 12?
Der eigentliche Grund für die Bools ist, dass man einen richtigen, boolschen statt binären, postfix toggle Operator haben wollte: https://godbolt.org/z/GGrsrEoYP
1 | #include <stdio.h> |
2 | #include <stdbool.h> |
3 | |
4 | int main(int argc, char** argv){ |
5 | bool b = true; |
6 | for(int i=0; i<10; i++) |
7 | puts(b-- ? "On" : "Off"); |
8 | } |
Wf88 schrieb: > Wie ist das vorgegeben? Meckert der compiler dann, oder macht er einfach > still ein TRUE (1) aus der 12? Er macht ein TRUE (1) aus der 12. Der Vorteil von bool (oder BOOL) ist, dass die Absicht des Programmierers klar ist, unabhängig ob der darunterliegende Datentyp ein INT oder ein BYTE ist. // Hier weiss ich dass die Funktion TRUE liefert, wenn alles passt. // Im Fehlerfall wird FALSE zurückgeliefert. BOOL doSomething() // Hier liefert die Funktion üblicherweise 0, wenn alles passt. // Im Fehlerfall wird ein Fehlercode zurückgeliefert. INT doSomething()
Wf88 schrieb: > Rolf M. schrieb: >> b=12 geht aber eben nicht, weil b ein bool ist, der den Wert 12 nicht >> annehmen kann. > > Wie ist das vorgegeben? Meckert der compiler dann, oder macht er einfach > still ein TRUE (1) aus der 12? Eine Konvertierung von int nach bool macht wie oben angegeben aus 0 ein false, aus allem anderen ein true. Umgekehrt macht eine Konvertierung von bool nach int aus false eine 0 und aus true eine 1. Dabei können solche Konvertierungen implizit durchgeführt werden, also "still". Folgendes C-Programm gibt daher 1 aus:
1 | #include <stdio.h> |
2 | #include <stdbool.h> |
3 | int main() |
4 | {
|
5 | int i = 12; |
6 | bool b = i; |
7 | int j = b; |
8 | printf("%d\n", j); |
9 | }
|
:
Bearbeitet durch User
Udo K. schrieb: > // Hier liefert die Funktion üblicherweise 0, wenn alles passt. > // Im Fehlerfall wird ein Fehlercode zurückgeliefert. > INT doSomething() Oder bei getchar(): 0 .. 0xFF = gültiges Datenbyte EOF (-1) = end of file
Rolf M. schrieb: > Dabei können > solche Konvertierungen implizit durchgeführt werden, also "still". > Folgendes C-Programm gibt daher 1 aus: Die Konvertierungen können nicht nur implizit, also "still" durchgeführt werden, die werden grundsätzlich implizit, also "still" durchgeführt. Was dann zu der oben angemoserten Eigenschaft führt, das der Compiler nicht warnt. Oliver
Danke für die geduldigen Erläuterungen, auch wenn ich das aus den voran gegangenen Posts hätte heraus lesen können.
Oliver S. schrieb: > Rolf M. schrieb: >> Dabei können >> solche Konvertierungen implizit durchgeführt werden, also "still". >> Folgendes C-Programm gibt daher 1 aus: > > Die Konvertierungen können nicht nur implizit, also "still" durchgeführt > werden, die werden grundsätzlich implizit, also "still" durchgeführt. Man kann sie per Cast durchaus auch explizit machen, wenn man das will:
1 | bool b = (bool)i; |
Aber es ist in dem Fall nicht nötig, weil die implizite Konvertierung genauso geht. Peter D. schrieb: > Oder bei getchar(): > 0 .. 0xFF = gültiges Datenbyte > EOF (-1) = end of file Was überaus ungeschickt gemacht ist, denn char kann auch signed sein, also einen Wertebereich von -0x80 bis 0x7F haben.
Rolf M. schrieb: > Was überaus ungeschickt gemacht ist, denn char kann auch signed sein, > also einen Wertebereich von -0x80 bis 0x7F haben. Der Return-Wert von getchar() ist int. Schon der erste Kernighan-Ritchie benutzte
1 | int c = getchar(); |
Ein char ist hier überhaupt nicht im Spiel. Das K&R-Kopierprogramm
1 | int main () |
2 | {
|
3 | int c; |
4 | |
5 | while ((c = getchar()) != EOF) |
6 | {
|
7 | putchar (c) |
8 | }
|
9 | return 0; |
10 | }
|
funktioniert auch anstandslos auf Systemen, wo char signed sein kann. Die Verwendung von char in der Zuweisung wäre aber hier ein Fehler - nämlich des Programmierers, nicht der Bibliotheksfunktion.
:
Bearbeitet durch Moderator
Was aber nicht funktioniert:
1 | int c = getchar(); |
2 | |
3 | if (c == -1) |
4 | {
|
5 | Error() |
6 | }
|
7 | else if (c == 'ä') |
8 | {
|
9 | NeverCalled() |
10 | }
|
11 | else if (c == 'a') |
12 | {
|
13 | Ok() |
14 | }
|
:
Bearbeitet durch User
Doch, das mit dem Wertebereich von Char ist tatsächlich ein Problem, egal, ob ich die jetzt in ein int oder ein char packe. Ich konvertiere die dann immer erstmal nach unsigned char, bevor ich die weiter auswerte. Mir ist es schon passiert, dass ich ein Case in einem Switch hatte, und dann war das Zeichen negativ! Der Wert von EOF ist aber auch Implementationsspezifisch, der wird fast überall auf was ausserhalb vom char Bereich gesetzt, egal ob char nun in der Implementation signed oder unsigned ist. Der Wert von EOF ist also in der Regel kein Problem. Blöd ist nur, wenn man im selben Switch EOF und 0x80 prüfen will. Dann kann man nicht einfach nach "unsigned char" casten. Ok, '\x80' müsste dann eigentlich gehen. Aber so einen Fehler muss man erst mal finden!
Udo K. schrieb: > else if (c == 'ä') Bei ISO8859 funktioniert das durchaus. c hat dann nämlich einen positiven Wert, nämlich 0xE4 - auch wenn auf dem System char signed wäre. Beachte, dass Du "int c" geschrieben hast, nicht "char c". getchar() liefert folgenden Wertebereich: 0 bis 255, -1 bei EOF - auch auf Systemen, wo char signed ist. Ich wiederhole: bei getchar() ist überhaupt kein char im Spiel!
Daniel A. schrieb: > Mir ist es schon passiert, dass ich ein Case in einem > Switch hatte, und dann war das Zeichen negativ! Natürlich kann das passieren, wenn Du char als Type verwendest. Das hat aber nichts mit getchar() zu tun. Ich antwortete auf folgenden Satz: Rolf M. schrieb: > Was überaus ungeschickt gemacht ist, denn char kann auch signed sein, > also einen Wertebereich von -0x80 bis 0x7F haben. Dieser bezog sich auf getchar(). Und darauf habe ich geantwortet. Dass Du jetzt darauf ansprichst, weil Du mal den Fehler gemacht hast, einen signed char buffer zu verwenden, hat mit getchar() überhaupt nichts zu tun. Wenn Du Zeichen speichern(!) willst, dann natürlich unsigned char:
1 | int main () |
2 | {
|
3 | unsigned char buffer[20]; // Hier unsigned char verwenden! |
4 | int c; // hier int verwenden! |
5 | int i = 0; |
6 | |
7 | while ((c = getchar ()) != EOF) |
8 | {
|
9 | buffer[i++] = c; |
10 | if (i == 20 - 1) |
11 | {
|
12 | exit(1); // zu lang |
13 | }
|
14 | }
|
15 | buffer[i] = '\0'; |
16 | printf ("Die ersten 20 Zeichen: %s\n", buffer); |
17 | }
|
Aber zum Auswerten des Rückgabewertes von getchar() brauchst Du weiterhin ein int!
:
Bearbeitet durch Moderator
Ich hab gerade nochmal nachgesehen, was der Standard sagt. Die Zeichen die getchar zurückgibt sind tatsächlich als ob sie vorher nach unsigned char konvertiert wurden. Und EOF muss negativ sein, aber es muss nicht zwingend -1 sein.
Daniel A. schrieb: > Ich hab gerade nochmal nachgesehen, was der Standard sagt. Die Zeichen > die getchar zurückgibt sind tatsächlich als ob sie vorher nach unsigned > char konvertiert wurden. > Und EOF muss negativ sein, aber es muss nicht zwingend -1 sein. Eben. Wenn Du eine int-Variable nimmst, um den Rückgabewert von getchar() zu testen, bist Du immer im grünen Bereich. Von daher ist gar nichts "ungeschicktes" an der Funktion getchar(). Diese hat 1970 schon anstandslos mit Binärdateien funktioniert und funktioniert auch heute noch mit 8-Bit-Zeichensätzen wie ISO8859 oder UTF-8.
Was mir aber gerade aufgefallen ist, bei Zeichenkonstanten ist das nicht festgelegt, ob wohl die auch vom typ int sind. Hier ein Beispiel, wo es negativ raus kommt: https://godbolt.org/z/z8xG7G4Wv Vermutlich ist es das, was ich in der Regel verwechsle. Da nimmt man extra '' für Zeichen im Switch, und dann sind die negativ!
Frank M. schrieb: > Daniel A. schrieb: >> Mir ist es schon passiert, dass ich ein Case in einem >> Switch hatte, und dann war das Zeichen negativ! > > Natürlich kann das passieren, wenn Du char als Type verwendest. Das hat > aber nichts mit getchar() zu tun. Das war was anderes. Den Fehler mache ich definitiv nie. War wohl das Zeichen positiv, aber die Zeichenkonstante negativ.
:
Bearbeitet durch User
Daniel A. schrieb: > Da nimmt man extra '' für Zeichen im Switch, und dann sind die negativ! Ja, Du hast 0x80 durch die Hochkommas in einen (negativen) char gewandelt. Hier sieht man das ganz gut:
1 | #include <stdio.h> |
2 | int main(int argc, char** argv) |
3 | {
|
4 | printf("%d %d\n", '\x80', 0x80); |
5 | }
|
1 | $ cc a.c && ./a.out |
2 | -128 128 |
:
Bearbeitet durch Moderator
'\x80' ist aber vom type int: https://godbolt.org/z/Y5rj6Pq3G
1 | #include <stdio.h> |
2 | |
3 | int main(int argc, char** argv){ |
4 | printf("%zu %s\n", sizeof('\x80'), _Generic('\x80', char: "char", int: "int")); |
5 | }
|
Ausgabe:
1 | 4 int |
Frank M. schrieb: > Bei ISO8859 funktioniert das durchaus. c hat dann nämlich einen > positiven Wert, nämlich 0xE4 - auch wenn auf dem System char signed > wäre. Beachte, dass Du "int c" geschrieben hast, nicht "char c". Mein Verständnis ist: Char 'ä' ist signed ((char)0xE4 < 0), und wird implizit auf int gewandelt, damit habe ich eine negative Zahl. Der Rückgabewert von getchar ist aber immer positiv oder -1. Der Vergleich wird also schiefgehen. Aber für ASCII Zeichen, die ja alle positiv sind, passt die Funktion. Negative Zeichenkonstanten muss man auf (unsigned char)'ä' wandeln. Das kommt aber in der Praxis selten vor.
:
Bearbeitet durch User
Udo K. schrieb: > Mein Verständnis ist: Char 'ä' ist signed ((char)0xE4 < 0), und wird > implizit auf int gewandelt, damit habe ich eine negative Zahl. D "Hällo" ist ein char Array. Und dort kann das zweite Element negativ oder positiv sein (halt wie char implementiert ist, als signed oder unsigned) 'ä' ist ein integer. Und positiv, wenn es "im erweiterten ASCII" liegt. Wenn ich 'a' nun einem char zuweise, dann wird es in diesem char halt als signed oder unsigned interpretiert, aber erst dort.
Frank M. schrieb: > Rolf M. schrieb: >> Was überaus ungeschickt gemacht ist, denn char kann auch signed sein, >> also einen Wertebereich von -0x80 bis 0x7F haben. > > Der Return-Wert von getchar() ist int. Schon der erste Kernighan-Ritchie > benutzte int c = getchar(); Ja, das ist auch der korrekte Weg. Wf88 schrieb: > Udo K. schrieb: >> 'ä' > > Weil für ein 'ä' brauchst du anderes Charset als das default. Frank M. schrieb: > Rolf M. schrieb: >> Was überaus ungeschickt gemacht ist, denn char kann auch signed sein, >> also einen Wertebereich von -0x80 bis 0x7F haben. > > Dieser bezog sich auf getchar(). Und darauf habe ich geantwortet. Dass > Du jetzt darauf ansprichst, weil Du mal den Fehler gemacht hast, einen > signed char buffer zu verwenden, hat mit getchar() überhaupt nichts zu > tun. > > Wenn Du Zeichen speichern(!) willst, dann natürlich unsigned char: Wie "natürlich"? Der Typ für Text ist char. Alle Stringfunktionen wie printf() oder strcmp() arbeiten mit Arrays aus char, nicht aus unsigned char. Explizit sollte man die signedness nur angeben, wenn man damit rechnen oder Bitgefummel machen will, denn Text hat eigentlich keine Signedness. > Aber zum Auswerten des Rückgabewertes von getchar() brauchst Du > weiterhin ein int! Ja. Das Problem ist: char ist eigentlich der Texttyp. Wenn der signed ist, dann muss getchar() den Wert erst in einen unsigned char wandeln, was auch im Standard so steht. Spannender wird es z.B. bei toupper(). Sagen wir mal, ich möchte mit fgets() (das auch mit einem char* arbeitet) einen String einlesen und diesen dann per toupper() zeichenweise in Großbuchstaben wandeln:
1 | char c[100]; |
2 | fgets(c, 100, stdin); |
3 | for (size_t i = 0; c[i] != '\0'; ++i) |
4 | c[i] = toupper(c[i]); // undefined behavior! |
An toupper() dürfen nämlich außer EOF keine negativen Werte übergeben werden. Man muss erst nach unsigned char casten. Frank M. schrieb: > Daniel A. schrieb: >> Ich hab gerade nochmal nachgesehen, was der Standard sagt. Die Zeichen >> die getchar zurückgibt sind tatsächlich als ob sie vorher nach unsigned >> char konvertiert wurden. >> Und EOF muss negativ sein, aber es muss nicht zwingend -1 sein. > > Eben. Und genau das ist es, was ich meinte. Udo K. schrieb: > Frank M. schrieb: >> Bei ISO8859 funktioniert das durchaus. c hat dann nämlich einen >> positiven Wert, nämlich 0xE4 - auch wenn auf dem System char signed >> wäre. Beachte, dass Du "int c" geschrieben hast, nicht "char c". > > Mein Verständnis ist: Char 'ä' ist signed ((char)0xE4 < 0), und wird > implizit auf int gewandelt, In C ist 'ä' bereits vom Typ int. In C++ ist es vom Typ char, muss aber so wie du sagst für den Vergleich erst nach int konvertiert werden (Integer-Promotion). > damit habe ich eine negative Zahl. Der Rückgabewert von getchar ist aber > immer positiv oder -1. Der Vergleich wird also schiefgehen. Das ist richtig. > Aber für ASCII Zeichen, die ja alle positiv sind, passt die Funktion. > Negative Zeichenkonstanten muss man auf (unsigned char)'ä' wandeln. Oder halt umgekehrt den Rückgabewert von getchar() nach char wandeln. > Das kommt aber in der Praxis selten vor. Heutzutage mit UTF-8 gibt's kein 'ä' mehr. Bruno V. schrieb: > 'ä' ist ein integer. Und positiv, wenn es "im erweiterten ASCII" liegt. Nein, eben nicht. Wenn char signed ist, ist 'ä' ein int mit negativem Wert!
:
Bearbeitet durch User
Bauform B. schrieb: > Was haltet ihr von -funsigned-char? Nicht allzuviel, ich hab gern "selbst" (=direkt im Code) in der Hand, was ich mit einer Variablen mache, bzw wie diese interpretiert wird. Vielleicht habe ich den Sinn dieses Parameters aber auch nicht ganz verstanden, keine Ahnung...
Der C-Standard sagt, dass es alle Integer-Typen in einer signed- und einer unsigned-Variante gibt. Dabei gilt, dass der Default, wenn man nichts explizit angibt, immer signed ist - außer für char. Da ist es implementation-defined, also der Compiler darf das entscheiden. Aus Gründen der Konsistenz mit den anderen Integer-Typen ist char deshalb zumindest bei gcc meist signed. Da es aber eben compilerabhängig ist, sollte an sich die Verwendung am besten so sein: signed char - für einen kleinen Integer mit Vorzeichen unsigned char - für einen kleinen Integer ohne Vorzeichen char - für Text Allerdings scheinen manche ein Problem damit zu haben, wenn Textzeichen in einem signed-Typ gespeichert werden, obwohl das streng genommen egal sein sollte. Text braucht nur genug Bits, um ein Zeichen zu speichern. Wie diese Bits verwendet würden, wenn man damit rechnen würde, spielt ja keine Rolle. Auf der anderen Seite sind dann noch die oben genannten Funktionen, die wie schon gesagt eher ungeschickt definiert sind und nicht sonderlich gut zu einem signed-char passen. Daher wird der eine oder andere mit dieser Option char auf unsigned zwingen. Am Ende schreibe ich aber meine Programme lieber so, dass es keine Rolle spielt, ob char signed oder unsigned ist und damit auch dieser Kommandozeilenparameter überflüssig ist.
:
Bearbeitet durch User
Rolf M. schrieb: > ohne Vorzeichen char - für Text Ja. Es geht nicht um char als Variable (da kann ich ja vorschreiben, was ich will) sondern um Stringkonstanten und library-funktionen mit char. Da würden ja genug Beispiele genannt.
Bruno V. schrieb: > Es geht nicht um char als Variable (da kann ich ja vorschreiben, was > ich will) sondern um Stringkonstanten und library-funktionen mit char. Sinnigerweise sollten beide das gleiche verwenden.
Andreas B. schrieb: > Ineffizient. Ein Byte oder ein Wort lesen, dann die anderen Bits > ausmaskieren kostet Zeit und Code. Beim Schreiben genauso. Ausnahme: Der > Prozessor hat entsprechende Bit-Befehle, etwa MSC-51 oder bei ARM > Bitbanding. Letzteres wird aber nur stiefmütterlich unterstützt und ist > (deshalb?) bei neueren Typen gar nicht mehr vorhanden. C167 hatte auch Bitbefehle, da hätte das Sinn gemacht. Ist schon so lange her...ich weiß nicht mehr, ob der C-Compiler diese Befehle genutzt hat. Ansonsten ist die kleinste Zugriffseinheit bei den Prozessoren 1 Byte, 1 Wort, 1 Doppelwort usw...., abhängig von der Breite des Datenbus. Wie Andreas schrieb, würde es Code und Zeit kosten die Bits innerhalb eines Bytes zu maskieren. bool macht trotzdem Sinn in C: FALSE = 0; TRUE = !FALSE (also alles außer 0)
Richard R. schrieb: > bool macht trotzdem Sinn in C: > FALSE = 0; TRUE = !FALSE (also alles außer 0) Wenn es als Scherz gemeint ist, dann bitte Smiley ;-) TRUE ist hier 1. '!' bedeutet nicht "alles außer" sondern "0-->1, sonst -->0"
Bruno V. schrieb: > Richard R. schrieb: >> bool macht trotzdem Sinn in C: >> FALSE = 0; TRUE = !FALSE (also alles außer 0) > > Wenn es als Scherz gemeint ist, dann bitte Smiley ;-) > > TRUE ist hier 1. '!' bedeutet nicht "alles außer" sondern "0-->1, sonst > -->0" Ja, den Fehler sieht man erstaunlich häufig. x != 0 ist aber eben nicht das gleiche wie x == !0.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.