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 ?????
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.
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.
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:
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. :)
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.
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.
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.
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...
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
boolb=false;
2
charc='A';
3
inti=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 :-)
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. :´(
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)
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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()
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:
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.
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
intc=getchar();
Ein char ist hier überhaupt nicht im Spiel.
Das K&R-Kopierprogramm
1
intmain()
2
{
3
intc;
4
5
while((c=getchar())!=EOF)
6
{
7
putchar(c)
8
}
9
return0;
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.
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!
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!
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
intmain()
2
{
3
unsignedcharbuffer[20];// Hier unsigned char verwenden!
4
intc;// hier int verwenden!
5
inti=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!
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.
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!
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.
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
charc[100];
2
fgets(c,100,stdin);
3
for(size_ti=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.
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.
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.
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.
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.
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)