Christoph Zurnieden: kennt sich jemand mit C aus?

Beitrag lesen

Hi,

sehr schön ausgeführt, für meinen Geschmack schon etwas *zu* schulmeisterlich, aber das ist Geschmackssache.

Es ist recht eng hier im Forum, da bleibt wenig Raum für so ausführliche Anmerkungen, wie man es eigentlich gerne schriebe. Da entsteht gerne Mal der Eindruck der Beckmesserei, der ist aber keineswegs beabsichtigt.

#define ANZ 20

Hier fehlt der kurze Kommentar, was diese Nummer machen soll.

"Fehlt" ist ziemlich stark formuliert. Da könnte man meinen, der Kommentar sei Pflicht. Sinnvoll und sehr empfehlenswert ist er aber allemal.

Wenn Du mit anderen Leuten zusammenarbeitest, ob jetzt oder in Zukunft, oder den Code einfach nur veröffentlichst, oder in ein paar Jahren selber noch verstehen möchtest, dann ist das einfach Pflicht. Da beschwert sich kein Compiler oder Lint, nur derjenige, der sich die Daten mühselig zusammensuchen muß, aber auch sowas nenne ich Pflicht.

{

Geschweifte Klammern auf eine neue Zeile zu setzen kann zu Unfällen führen. War erst neulich hier im Forum.

Ich weiß jetzt nicht, auf welchen Fall du ansprichst.

Bin jetzt zu faul zum Suchen, aber das war ungefähr so:

for(int i=0;i<100;i++);
  {
  printf("Inner Loop\n");
  }

"Der gibt nix aus, woran liegt's?" war ungefähr die Frage.

Nur das im Loop halt noch sehr viel mehr als nur ein printf() ausgeführt wurde.

Kannst ja mal im Archiv nach meinem Namen und "Indian Hill Style" (am Besten in Variationen;-) suchen. Ist vielleicht zwei Wochen her.

Wenn ich fremden Programmcode durchgehen muss, gibt es für mich kaum was Schlimmeres, als eine öffnende Klammer, die noch so unauffällig am Zeilenende steht. Da übersehe ich sie nämlich leicht.

Dann wechsle Deinen Editor.
Nein, wirklich: Blöcke, Semantik im Allgemeinem, sollte ein Editor gut darstellen können, sonst taugt er nicht viel.

char string[ANZ+1], c=(char)(0); // oder c = '\0'

Die Typen char und int sind zuweisungskompatibel, deswegen halte ich die Schreibweise '\0' eigentlich für unnötig kompliziert, genauso wie einen type cast zwischen int und char.

Ja, wenn das alles so einfach wäre ;-)
So funktioniert das nur auf einem PC o.ä., wenn Du auf "exotischere" Platformen umschwenkst kannst Du damit ganz gewaltig auf die Schnauze fallen.
Ein Byte ist nicht überall 8 Bit lang, ein int nicht überall 32 Bit, aber ein char entspricht einem Byte und ein Byte ist groß genug ein Zeichen der jeweiligen Umgebung zu halten:

3.4
1 byte
addressable unit of data storage large enough to hold any member of the basic characterset of the execution environment
2 NOTE 1 It is possible to express the address of each individual byte of an object uniquely.
3 NOTE 2 A byte is composed of a contiguous sequence of bits, the number of which is implementation­ defined. The least significant bit is called the low­ order bit; the most significant bit is called the high­order bit.

Was Du meinst ist wahrscheinlich "integer promotions", d.h. das Du z.B. zwei chars einfach addieren kannst.

Nebenbei: was ist mit dem Unterschied von uchar und char? Du kann sowas machen: char c = 'ä', aber was dabei rauskommt ist fraglich, wenn es nicht bereits eine Compilerwarnung bekommt.

memset(string,'\0',ANZ+1);

Wenn schon, dann:
char string[ANZ+1] = "";
Selbst das ist Standard.

Ja, stimmt, ist wohl alte Gewohnheit bei mir ;-)

Arrayelemente (in diesem Fall chars), die bei der Initialisierung nicht explizit einen Wert erhalten, werden mit 0 belegt (oder '\0' oder NULL, je nachdem was dir am liebsten ist).

Nein, das stimmt wieder nicht.

6.7.8 Initialization
[...]
10 If an object that has automatic storage duration is not initialized explicitly,its value is indeterminate. If an object that has static storage duration is not initialized
explicitly, then:
---if it has pointer type, it is initialized to a null pointer;
---if it has arithmetic type, it is initialized to (positive or unsigned) zero;
---if it is an aggregate, every member is initialized (recursively) according to these rules;
---if it is a union, the first named member is initialized (recursively) according to these rules.
[...]
14 An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

Also

char string[ANZ+1] = "";

entspricht nach neuem Standard

char string[ANZ+1];
memset(string,'\0',ANZ+1);

was ich mir noch nicht so ganz angewöhnt habe, jedoch

char string[ANZ+1];

alleine reicht dafür nicht.

BTW: ein cast wäre hier eigentlich angesagt:
}while(c!=(char)(13));

Überflüssig. Macht die Sache IMHO nur schwerer zu lesen.

Ich finde eher das Gegenteil. Hier macht das nix, aber wenn der Loop recht lang ist, wäre so ein cast schon hilfreich.

BTW: ganz vergessen, das hier die 13 als kommentiertem #define besser aufgehoben gewesen wäre. So eine nackte Zahl sagt wenig, aber z.B. RETURNKEY o.ä. ist recht aussagekräftig und kann vor allem auch einfach nachgesucht werden (find, grep u. Konsorten)

Aber die getchar()-Funktion liefert unabhängig davon den "reinen" ASCII-Code, der der Taste zugeordnet ist.

Nein, definitiv nicht. getchar() ist nix anderes als getc(stdin), was nix anderes als fgetc(stdin) ist. Es wird also nur ein char (genauer: ein auf _unsigned_ char gecasteter int!) zurückgegeben, das aus dem Dateistrom namens "stdin" gelesen wurde. Das kann durchaus ASCII-Code sein, oder 8-Bit Codierung oder wwi. Es muß noch nicht einmal eine Taste gedrückt worden sein, davon hat C eh keine Ahnung.

Bei der Enter-Taste ist das generell '\r' (oder 13 oder '\x0D').

Das sagt wer? Wo steht das? In meinem C-99 Standard steht nix davon.

Erst wenn man das jetzt auch noch ausgeben will, muss man aufpassen, weil putchar() das Zeichen uninterpretiert ausgibt. Hier kann man also beim gleichen Zeichen plattformabhängig verschiedene Ergebnisse erhalten.

Ja, da kann ich nur beipflichten, aber das ist rein gar kein Unterschied zu getchar(), der macht das Gleiche.

Bei printf() ist es wieder anders: Hier wird '\n' (oder 10 oder '\x0A') automatisch in das Zeichen oder die Zeichenfolge konvertiert, die auf dem jeweiligen System eine neue Zeile erzeugt. Unter MS-Betriebssystemen also in "\r\n".

So sollte es sein, so steht es im Standard, ja.
Nur gilt das (vid. 5.2.2 Character display semantics) nicht nur für printf() sondern z.B. logischerweise auch für scanf(). Das ist dann aber eines der Dinge auf die ich mich nicht unbedingt blind verlassen würde ;-)
(Geht auch erfahrungsgemäß in die Hose sowas)

Ich hoffe, du fühlst dich jetzt nicht angegriffen oder so; ich wollte nur deutlich machen, dass manches, was du hier empfohlen hast, eigentlich übervorsichtig ist - oder eben Geschmackssache. ;)

Üebr Geschmack läßt sich trefflich streiten, ja, aber als übervorsichtig würde ich mich nicht sehen. Standard-C ist nunmal die portabelste Sprache und wird jetzt wieder zunehmend für embedded Systems modern. Da kann man sich keine Nachlässigkeiten leisten, da muß man Standard-C oder sogar ANSI-C schreiben. Wenn das nicht eh schon direkt baut, so reichen doch stets einige wenige Handgriffe zur Anpassung.

Deshalb sollte der Anfänger Standard-C lernen und kein Windows-C, DOS-C, Linux-C oder was weiß ich alles. Das ist auch einfach zu lernen, da das nicht sehr viel ist. Wenn das dann sitzt, dann und wirklich erst dann kann man damit anfangen systemspezifische Erweiterungen einzuführen.

so short

Christoph Zurnieden