Forum: Compiler & IDEs Aus '\n' wird '\0'


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
ich nutze gerade den ARM-GCC und habe folgende, wahnsinnig komplizierte 
Funktion:
1
void printme(void)
2
{
3
    printf("\fPWM test PC9\n");
4
    printf("PWM test PC9\n"); // |<-- der Ausdruck muss genauso bleiben.
5
}
Schaue ich mir die Zeichenkette im Binary an, steht da allerdings:
1
0000A7F0  00 00 00 00 0C 50 57 4D 20 74 65 73 74 20 50 43  .....PWM test PC
2
0000A800  39 00 00 00 50 57 4D 20 74 65 73 74 20 50 43 39  9...PWM test PC9
d.h. das Newline am Ende wird zu einem '\0' gemacht.

Deshalb meine an die Wissenden:

 - Handelt es sich um gewünschtes Verhalten (irgendeine schwierig zu 
findende Definition von printf) ?

 - Wie kann ich den Compiler dazu bringen, das zu machen, was ich bei 
obigem Quelltext naiv erwartet hätte? Der Umbruch muß im oberen String 
bleiben. Momentan behelfe ich mir mit:
1
    printf("\fPWM test PC9\n \b");
2
    printf("PWM test PC9\n");

Viele Grüße
W.T.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Der Compiler wird Deine printf -Aufrufe durch effektivere puts 
-Aufrufe ersetzen (denn Deine "Formatstrings" enthalten keine 
Formatanweisungen und Du übergibst auch keine auszugebenden Variablen) 
-- und puts hängt das abschließende \n selbst an. Also kann es in der 
Stringkonstante weggelassen werden.

: Bearbeitet durch User
von g457 (Gast)


Lesenswert?

Hast Du puts() selbst implementiert? Falls ja isses kaputt, falls nein 
höchstwahrscheinlich auch :-)

von Jim M. (turboj)


Lesenswert?

Walter Tarpan schrieb:
> - Handelt es sich um gewünschtes Verhalten

Ja. Denn das "printf" wird durch ein "puts" ersetzt, welches das \n 
automagisch anfügt. Das müsste bei GCC auch irgendwo so dokumentiert 
sein.

Walter Tarpan schrieb:
> Der Umbruch muß im oberen String
> bleiben.

Darf ich fragen: Wieso?

von hp-freund (Gast)


Lesenswert?

Walter Tarpan schrieb:
> printf("PWM test PC9\n"); // |<-- der Ausdruck muss genauso bleiben.

1
char text[] = "PWM test PC9\n";
2
.
3
.
4
printf("%s",text);

Dann ist er in Silizium gebrannt ;-)

von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

Rufus Τ. Firefly schrieb:
> und puts hängt das abschließende \n selbst an.

danke für die Erinnerung! Das wird es sein.

g457 schrieb:
> Hast Du puts() selbst implementiert? Falls ja isses kaputt, falls nein
> höchstwahrscheinlich auch :-)

Ja, die Implementierung der stdio-Funktionen etwas kaputt. Nicht nur an 
dieser Stelle. (z.B. spielt sie total verrückt, wenn eine Zeichenkette 
mit nur einem Zeichen mit printf ausgegeben wird oder das 
Leerzeichen-Flag zur Formatierung verwendet wird). Sie lag CooCox bei.

Und so sieht sie aus:
1
/**
2
 * @brief  Outputs a string on stdout.
3
 *
4
 * @param pStr  String to output. 
5
 */
6
signed int puts(const char *pStr)
7
{
8
    return fputs(pStr, stdout);
9
}
10
11
12
/**
13
 * @brief  Implementation of fputs using the DBGU as the standard output. Required
14
 *         for printf().
15
 *
16
 * @param pStr     String to write.
17
 * @param pStream  Output stream.
18
 *
19
 * @return  Number of characters written if successful, or -1 if the output
20
 *          stream is not stdout or stderr.
21
 */
22
signed int fputs(const char *pStr, FILE *pStream)
23
{
24
    signed int num = 0;
25
26
    while (*pStr != 0) {
27
28
        if (fputc(*pStr, pStream) == -1) {
29
30
            return -1;
31
        }
32
        num++;
33
        pStr++;
34
    }
35
36
    return num;
37
}

Dann werde ich mal puts oder fputs (muß mal nachsehen, wer das 
Leerzeichen normalerweise erzeugt) entsprechend ergänzen. Danke fürs 
Lesen und die Ratschläge.

W.T.

von Walter T. (nicolas)


Lesenswert?

hp-freund schrieb:
> Walter Tarpan schrieb:
>> printf("PWM test PC9\n"); // |<-- der Ausdruck muss genauso bleiben.
>
>
>
1
> char text[] = "PWM test PC9\n";
2
> .
3
> .
4
> printf("%s",text);
5
>
>
> Dann ist er in Silizium gebrannt ;-)

Genau. Ich hatte nur, um das Beispiel kürzer zu gestalten die zweite 
Zeile zu dem geändert, was oben im Post steht.

von Walter T. (nicolas)


Lesenswert?

Und der Nachtrag: Hab's gefunden. fputs gibt kein Newline aus, aber 
puts. Das läßt sich ja dann leicht implementieren.

von Falk B. (falk)


Lesenswert?

@ Walter Tarpan (nicolas)

>{
>    printf("\fPWM test PC9\n");
>    printf("PWM test PC9\n"); // |<-- der Ausdruck muss genauso bleiben.
>}

>0000A7F0  00 00 00 00 0C 50 57 4D 20 74 65 73 74 20 50 43  .....PWM test PC
>0000A800  39 00 00 00 50 57 4D 20 74 65 73 74 20 50 43 39  9...PWM test PC9

>d.h. das Newline am Ende wird zu einem '\0' gemacht.

Dann ist printf() ein Makro, das einen String vor dem echten Compilieren 
konvertiert und das \n entfernt. Ein normaler Compiler schmeißt das \n 
nicht raus.

von F. F. (foldi)


Lesenswert?

Mal eine blöde Frage zu den Optimierungsmöglichkeiten eines Compilers.
Wenn man grundsätzlich eine Optimierung möchte, aber an bestimmten 
Punkten nicht, kann man das ins Programm schreiben, bzw. gibt es ein 
Möglichkeit dem Compiler das mitzuteilen, so wie bei sei () und cli () 
für die Interrupts?

von Stephan (Gast)


Lesenswert?

hier 2 Beispiele:
1
#pragma GCC push_options
2
#pragma GCC optimize ("O0")
3
4
your code
5
6
#pragma GCC pop_options
und
1
void __attribute__((optimize("O0"))) foo(unsigned char data) {
2
    // unmodifiable compiler code
3
}

gefunden bei:
http://stackoverflow.com/questions/2219829/how-to-prevent-gcc-optimizing-some-statements-in-c

von hp-freund (Gast)


Lesenswert?


von F. F. (foldi)


Lesenswert?

Toll, vielen Dank!

von Yalu X. (yalu) (Moderator)


Lesenswert?

Falk Brunner schrieb:
> Dann ist printf() ein Makro, das einen String vor dem echten Compilieren
> konvertiert und das \n entfernt.

Genauer gesagt, ist es eine eine Built-In-Funktion des GCC. Solche
Built-In-Versionen gibt es auch für viele andere Funktionen aus der
Standardbibliothek und sind eigentlich eine feine Sache, da sie dem
Compiler Optimierungsmöglichkeiten eröffnen, die er ohne sie nicht 
hätte.

Sollten sie doch einmal stören, lassen sie sich mit -fno-builtin oder
-fno-builtin-<funktionsname> abschalten.

> Ein normaler Compiler schmeißt das \n nicht raus.

Was ist heutzutage noch normal? ;-)

von Falk B. (falk)


Lesenswert?

@ Yalu X. (yalu) (Moderator)

>> Dann ist printf() ein Makro, das einen String vor dem echten Compilieren
>> konvertiert und das \n entfernt.

>Genauer gesagt, ist es eine eine Built-In-Funktion des GCC.

Aber das normale printf() im avr gcc schmeißt das \n doch nicht raus, 
oder?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Das \n wird nur dann hinausgeschmissen, wenn der Compiler den printf-
durch einen puts-Aufruf ersetzt, da puts im Gegensatz zu printf die
Ausgabe schon von sich aus mit einem \n abschließt. Am Verhalten des
Programms ändert sich dadurch überhaupt nichts.

Anderes Beispiel:
1
  printf("X");

wird vom GCC in
1
  putchar('X');

umgesetzt.

In diesem Fall fällt sogar die komplette Stringkonstante weg,
stattdessen wird der Zeichencode von 'X' direkt als Argument übergeben.

: Bearbeitet durch Moderator
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.