Forum: PC-Programmierung char initialisierung in C


von Koe (Gast)


Lesenswert?

Hi,

Ich lese gerade "Softwareentwicklung in C"
http://www.asc.tuwien.ac.at/eprog/download/schmaranz.pdf

Auf Seite 37 wird ein unsinged char folgendermassen initialisiert:
1
unsigned char a_uchar_= '\0';

Aus welchem Grund wird ein char mit Anfürungszeichen und mit einer 
Escape Sequenz initialisiert ?
1
unsigned char a_uchar_= 0;

Bewirkt doch das selbe, oder nicht ?


Mfg Koe

von nfet (Gast)


Lesenswert?

Ja, aber mit der ersten Schreibweise macht man klarer, dass man gedenkt 
sein char als Buchstaben und nicht als Zahl zu benutzen.

von Koe (Gast)


Lesenswert?

nfet schrieb:
> Ja, aber mit der ersten Schreibweise macht man klarer, dass man
> gedenkt
> sein char als Buchstaben und nicht als Zahl zu benutzen.

Hab ich mir gedacht. Besten Dank.

von Dirk B. (dirkb2)


Lesenswert?

Hier ist das aber etwas merkwürdig, da man für Zeichen  nur char als 
Typ verwenden sollte.

Hier ist aber unsigned char angegeben.

von Matthias L. (Gast)


Lesenswert?

Gibt es auch negative (ASCII-)Zeichen?

von Mark B. (markbrandis)


Lesenswert?

nfet schrieb:
> Ja, aber mit der ersten Schreibweise macht man klarer, dass man gedenkt
> sein char als Buchstaben und nicht als Zahl zu benutzen.

Dann ist das "unsigned" freilich nicht sinnvoll.

ASCII-Zeichen: char
Ganzzahlen von -128 bis +127: signed char
Ganzzahlen von 0 bis 255: unsigned char

: Bearbeitet durch User
von Tom (Gast)


Lesenswert?

Dirk B. schrieb:
> Hier ist das aber etwas merkwürdig, da man für Zeichen  nur char als
> Typ verwenden sollte.

Das Buch ist alt und enthält selbst für sein Alter ziemliche 
oldschool-Konstrukte. Im Vorwort wird zwar darauf herumgeritten, dass es 
um sinnvolle Software-Entwicklung geht und nicht nur um das C-Lernen, 
aber es kommen ständig Kracher wie
1
main()
2
{
3
  printf( "Hello World!\n");
4
}
,
1
#define SWAP(a, b) {int swap = a; a = b; b = swap;}
oder Beispielprogramme, die ausschließlich (unnötig) globale Variablen 
enthalten, vor.

von Marc (gierig) Benutzerseite


Lesenswert?

Koe schrieb:

> unsigned char a_uchar_= '\0';
> unsigned char a_uchar_= 0;

> Bewirkt doch das selbe, oder nicht ?

NEIN,
das eine ist 0x00 oder auch bekannt als NULL,
das andere ist 0x30 ASCII für die Zahl Null.

Damit ist es ein Unterschied.

von Klaus W. (mfgkw)


Lesenswert?

In der Tat ist es sinnvoll, char zu verwenden und nicht signed oder 
unsigned char, solange man wirklich Zeichen damit speichern will.
Schon aus dem einfachen Grund, weil alle einschlägigen 
Bibliotheksfunktionen nicht signed oder unsigned char, sondern halt char 
verwenden und man unnötiges Casten und Gemecker vermeidet.

signed char oder unsigned char macht nur Sinn, wenn man den Typ nicht 
für Zeichen benutzt, sondern konkret damit rechnet, also einfach als 
kleine Zahl nutzt.
Ob der Name des Datentyps sinnvoll ist, sei dahingestellt - ist halt so.

von Peter II (Gast)


Lesenswert?

Marc D. schrieb:
> Koe schrieb:
>
>> unsigned char a_uchar_= '\0';
>> unsigned char a_uchar_= 0;
>
>> Bewirkt doch das selbe, oder nicht ?
>
> NEIN,
> das eine ist 0x00 oder auch bekannt als NULL,
> das andere ist 0x30 ASCII für die Zahl Null.
>
> Damit ist es ein Unterschied.

wo sieht du hier ein  "0x30 ASCII für die Zahl Null"??

von Mikro 7. (mikro77)


Lesenswert?

1
unsigned char a_uchar_= '\0';
Initialisierung mit char Literal.
1
unsigned char a_uchar_= 0;
Initialisierung mit int Literal.
(läuft beides praktisch auf das gleiche hinaus.)

: Bearbeitet durch User
von Der Andere (Gast)


Lesenswert?

Marc D. schrieb:
> NEIN,
> das eine ist 0x00 oder auch bekannt als NULL,
> das andere ist 0x30 ASCII für die Zahl Null.
>
> Damit ist es ein Unterschied.

Unfug, erst selbst C lernen.
S.J. hat es korrekt formuliert.

unsigned char a_uchar_= '0';
würde die Variable mit 0x30 für die ZIFFER NULL initialisieren.

von Marc (gierig) Benutzerseite


Lesenswert?

Peter II schrieb:
> wo sieht du hier ein  "0x30 ASCII für die Zahl Null"??

Asche auf das Haupt deren die unwürdig sind und nicht nachdenken
bevor sie schreiben: namentlich Mich.
Ist natürlich Schwachsinn was ich da verzapft habe ohne nachzudenken,
oder richtig zu lesen.

S.J hat natürlich recht.

: Bearbeitet durch User
von Dennis (Gast)


Lesenswert?

Marc D. schrieb:
> Asche auf das Haupt deren die unwürdig sind und nicht nachdenken
> bevor sie schreiben: namentlich Mich.

Ist ja erst Dienstag. Die Woche ist noch lang, hast also noch Zeit 
wachzuwerden :-)

von Dirk B. (dirkb2)


Lesenswert?

Matthias L. schrieb:
> Gibt es auch negative (ASCII-)Zeichen?
Bei ASCII: nein.
Sonst: möglicherweise. Das ist Darstellungssache. (Wie wird das 
Bitmuster als Zahlenwert interpretiert)

von Matthias L. (Gast)


Lesenswert?

Dirk B. schrieb:
> Sonst: möglicherweise. Das ist Darstellungssache. (Wie wird das
> Bitmuster als Zahlenwert interpretiert)

Logisch. Letztendlich sind Strings nur Zahlenarrays die als ASCII 
interpretiert werden. Ich verwende dafür immer ein u8.

Warum sollte man da signed verwenden?

von Peter II (Gast)


Lesenswert?

Matthias L. schrieb:
> Warum sollte man da signed verwenden?

weil es Compiler geben kann, die char als signed definiert haben. Damit 
musst du sonst immer casten.

von (prx) A. K. (prx)


Lesenswert?

Marc D. schrieb:
> das eine ist 0x00 oder auch bekannt als NULL,

NULL ist für Pointer reserviert. Das ist also Unfug:
  unsigned char a_uchar_= NULL;
obwohl ich das gelegentlich schon gesehen habe.

: Bearbeitet durch User
von So ein verdammter Murks (Gast)


Lesenswert?

>> Gibt es auch negative (ASCII-)Zeichen?
>Bei ASCII: nein.

Die USA benutzen nur 7 Bit - ob das 8. Bit als negative Zahl 
interpretiert wird ist denen egal. In Deutschland wird das 8. Bit für 
Umlaute benutzt.

Der größte Murks, den jemals ein Amerikaner erfunden hat.
1
int[] characterType = {....};
2
char c = getc();
3
int type = characterType[c];

Funktioniert mit 7 Bit Ascii einwandfrei. Ob es in Deutschland 
funktioniert, hängt davon ab, ob der Compiler char als signed oder 
unsigned behandelt.

von Walter T. (nicolas)


Lesenswert?

Deswegen definiert man c auch nicht als char sondern als size_t.

von Ano (Gast)


Lesenswert?

So ein verdammter Murks schrieb:
>>> Gibt es auch negative (ASCII-)Zeichen?
>>Bei ASCII: nein.
>
> Die USA benutzen nur 7 Bit - ob das 8. Bit als negative Zahl
> interpretiert wird ist denen egal. In Deutschland wird das 8. Bit für
> Umlaute benutzt.

Kommt drauf an was für ein Zeichensatz verwendet wird. Die gängigen 
(UTF-8 und UTF-16) brauchen 2 Byte für Umlaute. ISO-Codepages sind eher 
Altlasten die nicht mehr verwendet werden sollten.

von Rolf M. (rmagnus)


Lesenswert?

Matthias L. schrieb:
> Dirk B. schrieb:
>> Sonst: möglicherweise. Das ist Darstellungssache. (Wie wird das
>> Bitmuster als Zahlenwert interpretiert)
>
> Logisch. Letztendlich sind Strings nur Zahlenarrays die als ASCII
> interpretiert werden. Ich verwende dafür immer ein u8.
>
> Warum sollte man da signed verwenden?

Man benutzt weder explizit signed noch unsigned, sondern einfach nur 
char. Was der Compiler dafür als interne Repräsentation verwendet, kann 
einem völlig egal sein, da man damit sowieso nicht rechnet.
Also ist ein char mit Vorzeichen genauso sinnvoll oder sinnlos wie einer 
ohne.

So ein verdammter Murks schrieb:
> Der größte Murks, den jemals ein Amerikaner erfunden hat.
> int[] characterType = {....};
> char c = getc();
> int type = characterType[c];
>
> Funktioniert mit 7 Bit Ascii einwandfrei. Ob es in Deutschland
> funktioniert, hängt davon ab, ob der Compiler char als signed oder
> unsigned behandelt.

Deshalb macht man das auch nicht so. Man muß es in C halt machen, wie in 
vielen anderen Sprachen auch: Wenn ich einen Zahlenwert haben will, muß 
ich eine geeignete Typkonvertierung machen. Der einzige Unterschied ist, 
daß man bei C (anders als z.B. in Pascal) auch direkt an den internen 
Wert der char-Variable kommt.

von Yalu X. (yalu) (Moderator)


Lesenswert?

So ein verdammter Murks schrieb:
> Der größte Murks, den jemals ein Amerikaner erfunden hat.
>
>  int[] characterType = {....};
>  char c = getc();
>  int type = characterType[ c];

Du meinst wahrscheinlich
1
  int characterType[] = {....};
2
  char c = getchar();
3
  int type = characterType[c];

getchar liefert ein int, als Array-Index wird ein size_t erwartet.
Deklariert man c als einen diese beiden Typen, funktioniert das Ganze
auch mit 8-Bit-Zeichencodierungen. char als Datentyp für c ist hier
aber völlig fehl am Platz.

von Daniel A. (daniel-a)


Lesenswert?

Yalu X. schrieb:
> getchar liefert ein int, als Array-Index wird ein size_t erwartet.

Wie ist dass zu verstehen? Meines wissens gibt es keine Vorgabe mit 
welchen arithmetischen Datentypen die Arraysubscription durchgeführt 
werden sollte. Es gillt sogar ""[0] ist equivalent zu *(""+0) und zu 
0[""]

> Deklariert man c als einen diese beiden Typen, funktioniert das Ganze
> auch mit 8-Bit-Zeichencodierungen.

Das trifft zu, aber ich finde Code sollte immer funktionieren, und nicht 
nur wenn gewisse Annahmen zutreffen. Ich würde c in diesem Beispiel als 
'unsigned int' definieren, da dieser Datentyp gleichgross ist wie ein 
int, aber nicht negativ sein kann, und mit sizeof prüfen ob etwas an dem 
Arrayindex steht:
1
  int characterType[] = {....};
2
  unsigned c = getchar();
3
  int type = 0;
4
  if( c < sizeof(characterType)/sizeof(*characterType) )
5
    type = characterType[c];

size_t gefällt mir hier nicht, weil der Wertebereich in keinem 
zusammenhang zu dem der Eingabedaten (ein int von getchar) steht.

von Karl H. (kbuchegg)


Lesenswert?

Yalu X. schrieb:

> getchar liefert ein int,

Schon richtig.
Aber der Hintergrund ist ein anderer.
getchar liefert prinzipiell schon einen char (promomted nach int), hat 
aber die Notwendigkeit auch EOF liefern zu können. Und damit ist der 
Wertebereich, den getchar liefern können muss um 1 über dem Wertebereich 
von char. Deshalb ist der Return Wert ein int.

> Deklariert man c als einen diese beiden Typen, funktioniert das Ganze
> auch mit 8-Bit-Zeichencodierungen.

Da EOF meistens als -1 codiert ist, gibt es dann allerdings Probleme, 
wenn das nicht vorher ausgefiltert wird.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Daniel A. schrieb:
> Yalu X. schrieb:
>> getchar liefert ein int, als Array-Index wird ein size_t erwartet.
>
> Wie ist dass zu verstehen? Meines wissens gibt es keine Vorgabe mit
> welchen arithmetischen Datentypen die Arraysubscription durchgeführt
> werden sollte.

Ja, es gibt lediglich die Vorgabe, dass der Index "integer type" haben
muss. Damit ist von signed char bis zu long long int alles erlaubt.
Aber natürlich sollte der Wertebereich des verwendeten Typs groß genug
sein, um die gesamte Array-Größe abzudecken. Der Wertebereich eines
vorzeichenbehafteten char reicht aber üblicherweise nur bis 127. Mit
size_t ist man aber immer auf der sicheren Seite, da kein Array mehr
als size_t Elemente enthalten kann (sonst würde der sizeof-Operator
nicht mehr funktionieren).

Karl H. schrieb:
> Schon richtig.
> Aber der Hintergrund ist ein anderer.

Auf jeden Fall ist es in obigem Beispiel unsinnig, ein char zu nehmen,
da dieses dort weder als Array-Index taugt noch die Unterscheidung
zwischen dem Zeichen '\xff' und EOF erlaubt (wenn man eine entsprechende
Abfrage einbauen wollte).

von Klugscheißer (Gast)


Lesenswert?

Yalu X. schrieb:
> Ja, es gibt lediglich die Vorgabe, dass der Index "integer type" haben
> muss. Damit ist von signed char bis zu long long int alles erlaubt.

Nicht zu vergessen: bool.
Das ist auch ein "integer type".

von Peter II (Gast)


Lesenswert?

Klugscheißer schrieb:
> Nicht zu vergessen: bool.
> Das ist auch ein "integer type".

sollte aber auch kein Problem darstellen. ein bool was auf int gewandelt 
wird, wird eine 0 oder eine 1.

von Klugscheißer (Gast)


Lesenswert?

Peter II schrieb:

> sollte aber auch kein Problem darstellen.

Tut es ja auch nicht...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc D. schrieb:
> Koe schrieb:
>
>> unsigned char a_uchar_= '\0';
>> unsigned char a_uchar_= 0;
>
>> Bewirkt doch das selbe, oder nicht ?
>
> NEIN,
> das eine ist 0x00 oder auch bekannt als NULL,
> das andere ist 0x30 ASCII für die Zahl Null.

Beides leider falsch. Ersteres ist bekannt als NUL - mit einem L. Mit 
NULL, meist im Zusammenhang mit "Nullpointern" zu sehen, hat das 
überhaupt nichts zu tun.

Siehe auch:

   http://man7.org/linux/man-pages/man7/ascii.7.html

Das andere ist nicht 0x30 ASCII, denn dann hätte man es '0' (mit 
Hochkommata) schreiben müssen. Wurde es aber nicht. 0 ist 0 und nix 
anderes. Beide Zuweisungen ergeben denselben Code.

: Bearbeitet durch Moderator
von (prx) A. K. (prx)


Lesenswert?

Frank M. schrieb:
> Beides leider falsch. Ersteres ist bekannt als NUL - mit einem L. Mit
> NULL, meist im Zusammenhang mit "Nullpointern" zu sehen, hat das
> überhaupt nichts zu tun.

Es hätte gepasst, hätte er NULL kleingeschrieben. Denn C nennt das 
offiziell den "null character".

von Rolf M. (rmagnus)


Lesenswert?

Frank M. schrieb:
>> das eine ist 0x00 oder auch bekannt als NULL,
>> das andere ist 0x30 ASCII für die Zahl Null.
>
> Beides leider falsch. Ersteres ist bekannt als NUL - mit einem L. Mit
> NULL, meist im Zusammenhang mit "Nullpointern" zu sehen, hat das
> überhaupt nichts zu tun.

Das ist durchaus als Definition für NULL erlaubt:
1
#define NULL 0x00

Allerdings nutzt man NULL beser nur im Zeigerkontext.

von Daniel A. (daniel-a)


Lesenswert?

Ich verwende immer 0x0 statt NULL, da dies ein define oder include spart 
und bei NULL nicht sofort klar ist, ob daraus nun 0 oder ((void*)0) 
wird.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Das ist durchaus als Definition für NULL erlaubt:
>
1
> #define NULL 0x00
2
>


Natürlich ist das als NULL erlaubt. Ist auch meistens genau so 
definiert, siehe <stdio.h>.

Aber das Zeichen '\0' heisst NUL (mit einem L), so wie

  '\a' BEL (bell)
  '\b' BS  (backspace)
  '\t' HT  (horizontal tab)
  '\n' NL  (newline)
  '\v' VT  (vertical tab)
  '\f' FF  (formfeed)
  '\r' CR  (carriage return)

heisst.

Also ausführlich:

  '\0' NUL (null character)

Und NUL (das Zeichen) hat nichts mit NULL (dem Nullpointer) zu tun. Dass 
beide Werte in den meisten C-Programmierumgebungen den numerischen Wert 
0 haben, ist purer Zufall - aber meist bequem für den Programmierer.

Deshalb sollte man, wenn man das Zeichen meint, auch '\0' schreiben, 
z.B.
1
  char *s;
2
  ...
3
  *(s + 5) = '\0';    // terminate string here!

Und wenn man den Nullpointer meint, dann das:
1
  FILE * fp;
2
  char * filename = "foo.bar";
3
4
  fp = fopen (filename, "r");
5
6
  if (fp == NULL)
7
  {
8
      perror (filename);
9
      ...
10
  }
11
  ...

Aber ich käme nie auf die Idee,
1
  *(s + 5) = NULL
oder
1
  if (fp == '\0')

zu schreiben.

: Bearbeitet durch Moderator
von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Das ist durchaus als Definition für NULL erlaubt:

Yep. Aber das ist ebenfalls zulässig - und macht sich als Ersatz von 
'\0' dann nicht mehr sonderlich gut:
#define NULL ((void *)0)

http://c-faq.com/null/nullor0.html

: Bearbeitet durch User
von Marc (gierig) Benutzerseite


Lesenswert?

Da frage ich mich wie viel Asche Ihr noch über mich aus kippen wollt :-)
Aber ich bin ja selber Schuld, habe aber auch wieder was gelernt.

Bisher bin ich davon ausgegangen das
null = NULL = NUL = \0 = 0x00 = 0

und damit NUL nur eine Abkürzung von NULL ist.


Danke vor allem Frank für die kleine Schulung in Sachen NULL

: Bearbeitet durch User
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
Noch kein Account? Hier anmelden.