Forum: PC-Programmierung Steuerzeichen entfernen ^@


von Wurstbrot (Gast)


Lesenswert?

Hallo Zusammen,

ich versuche mich grade an dem EDK2 Framework von Tianocore.
Habe ein kleines Programm geschrieben, dass in der UEFI-Shell eine 
Benutzereingabe entgegen nimmt und diese wieder ausgeben soll.

Hier der Code:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdint.h>
4
int main()
5
{
6
  char str[30];
7
  
8
  printf("Eingabe:");
9
  gets(str);
10
  printf(str);
11
12
}

Wenn ich nun die Shifttaste drück und was eingebe, steht vor der Eingabe 
ein ^@.
Bestätige ich die Eingabe, wird nichts angezeigt.
Hat jemand eine Idee?

von Rolf M. (rmagnus)


Lesenswert?

Wenn dein stdout zeilengepuffert ist, wird auf einen Zeilenumbruch 
gewartet, bevor die Ausgaben auf dem Bildschirm erscheinen. Es kommt 
aber keiner, da gets den entfernt.

Der Code ist übrigens ein gutes Beispiel für Sicherheitslücken.
gets() sollte man niemals benutzen, da es die Größe des Eingabepuffers 
nicht prüfen kann. Du musst darauf vertrauen, dass der Benutzer nie mehr 
als 29 Zeichen eingibt, denn sonst schreibt dein Programm über das Ende 
des Arrays hinaus. Es ist in neueren Versionen von C auch inzwischen 
nicht mehr verfügbar. Zusätzlich sollte man niemals einen von außen 
gelesenen String als Formatstring bei printf() benutzen. Da kann man 
Format-Anweisungen hineinschreiben, die auch wieder wild auf 
Speicherstellen zugreifen können.
Besser wäre:
1
    printf("Eingabe:"); fflush(stdout);
2
    fgets(str, 30, stdin);
3
    printf("%s", str);

fgets entfernt das Newline am Ende übrigens nicht.

von Daniel A. (daniel-a)


Lesenswert?

Wurstbrot schrieb:
> Wenn ich nun die Shifttaste drück und was eingebe, steht vor der Eingabe
> ein ^@.
> Bestätige ich die Eingabe, wird nichts angezeigt.
> Hat jemand eine Idee?

Bei Terminals wird, wenn das echo Eingeschalten ist, und von der Eingabe 
ein Steuerzeichen kommt, normalerweise statdessen eine Escapesequenz 
angezeigt.
Bei ^@ wäre das ein null byte. Das ist auch der String Terminator in C.

Angenommen, da ist wirklich ein null byte in stdin, wirst du mit gets 
und fgets und printf alleine nicht weiterkommen. fread & getc müssten 
glaube ich gehen, vor der Ausgabe musst du die Sonderzeichen aber halt 
eventuell entfernen oder ersetzen, zumindest die Nullbytes, und du wirst 
dir zumindest beim Einlesen die Anzahl eingelesene Bytes merken müssen, 
falls du die Nullbytes nicht sofort herausfilterst.

von Wurstbrot (Gast)


Lesenswert?

Rolf M. schrieb:
> printf("Eingabe:"); fflush(stdout);
>     fgets(str, 30, stdin);
>     printf("%s", str);

Hallo Rolf,

ich habe Deinen Code mal getestet.
Leider funktioniert es auch damit nicht.
Als Ausgabe erhalte ich nun ein ^B

Eventuell gibt es ja auch einen andere Lösung.
Im Grunde muss ich in der UEFI Shell eine Benutzereingabe haben.
Unter DOS wäre das:

set /p %eingabe%="Eingabe: "

Leider funktioniert as nicht in UEFI.
Der set Befehl ist zwar bekannt, aber nicht mit dem Parameter /p
Das war der Grund, warum ich mir das EDK Framework angeschaut habe.

von Wurstbrot (Gast)


Lesenswert?

Daniel A. schrieb:
> fread & getc müssten
> glaube ich gehen

Hallo Daniel,

ich bin leider nicht so fit in C.
Im Netz habe ich neur Beispiele in Verbindung mit Streams gefunden.
Hättest Du vielleicht ein Beispiel dazu?

von 🐧 DPA 🐧 (Gast)


Lesenswert?

Versuche es mal hiermit, das liest die Eingaben zeichenweise ein, und 
gibt aus was genau es bekommen hat:
1
#include <ctype.h>
2
#include <stdio.h>
3
#include <stdbool.h>
4
5
int main()
6
{
7
8
  int i=0;
9
  char line[30];
10
11
  for(int c; (c=getchar()) != EOF; ){
12
13
    bool printable = isprint(c);
14
    printf("input: 0x%.2X%s\n", c, printable ? (char[]){' ',c,0} : "");
15
16
    if(printable){
17
      if(i >= sizeof(line)-1){
18
        printf("line buffer full: %s\n", line);
19
        i = 0;
20
      }
21
      line[i] = c;
22
      i += 1;
23
    }
24
25
    if(c == '\n' || c  == '\r'){
26
      line[i] = 0;
27
      i = 0;
28
      printf("line: %s\n", line);
29
    }
30
31
  }
32
33
}

von Wurstbrot (Gast)


Lesenswert?

🐧 DPA 🐧 schrieb:
> Versuche es mal hiermit, das liest die Eingaben zeichenweise ein, und
> gibt aus was genau es bekommen hat:

Hallo DPA,

ich bekomme einige Fehler ausgegeben.

Für die Zeile: for(int c; (c=getchar()) != EOF; ){

Bekomme ich:
Fehler  1  error C2143: Syntaxfehler: Es fehlt ';' vor 'Typ' 
d:\projekte\edk2\AppPkg\Applications\test\test.c  15  1  EDK2 Make
Fehler  2  error C2143: Syntaxfehler: Es fehlt ')' vor 'Typ' 
d:\projekte\edk2\AppPkg\Applications\test\test.c  15  1  EDK2 Make
Fehler  3  error C2065: 'c': nichtdeklarierter Bezeichner 
d:\projekte\edk2\AppPkg\Applications\test\test.c  15  1  EDK2 Make
Warnung  4  warning C4552: '!=': Operator hat keine Auswirkungen; 
Operator mit Nebeneffekt erwartet 
d:\projekte\edk2\AppPkg\Applications\test\test.c  15  1  EDK2 Make
Fehler  5  error C2059: Syntaxfehler: ')' 
d:\projekte\edk2\AppPkg\Applications\test\test.c  15  1  EDK2 Make

von Dirk B. (dirkb2)


Lesenswert?

Ist das noch C89-Standard?

Funktioniert für die for-Zeile:
1
int c;  while( (c=getchar()) != EOF ) {
?

von gets (Gast)


Lesenswert?

1
NAME
2
       gets - get a string from standard input (DEPRECATED)
3
4
DESCRIPTION
5
       Never use this function.

von Wurstbrot (Gast)


Lesenswert?

Dirk B. schrieb:
> Ist das noch C89-Standard?
>
> Funktioniert für die for-Zeile:int c;  while( (c=getchar()) != EOF ) {
> ?

Hallo Dirk.
Die Schleife funktioniert.

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.