Forum: Compiler & IDEs Abfrage ob Buffer zu ende ist.


von simon (Gast)


Lesenswert?

Ich habe hier eine Funktion die z.B. ein byte formatiert ausgibt:
1
void usart_write_P (const char *Buffer,...) {
2
3
  by = pgm_read_byte(Buffer++);
4
    if(by==0) break; // end of format string
5
6
}

Aufruf mit:
1
int u;
2
u = 0x00; (oder irgend ein anderer wert)
3
4
usart_write_P("receive: %i \n", (int) u);

Wieso kann man hier mit by==0 abfragen ob der Buffer zu Ende ist?
würde das nicht zu einem Problem führen wenn u == 0?

if(by==0) break;

von na (Gast)


Lesenswert?

'0' (0x30 im string) != 0x00 ('\0' als stringende)

in C wird 0x00 oft als Markierung für das Ende eines Strings genutzt, 
sofern deine usart_write_P() wie printf() arbeiten sollte, fügt auch sie 
das am Ende ein.

Lass dir auf einem PC vielleicht mal einen String als HEX ausgeben, 
damit du die einzelnen Bytes siehst

von simon (Gast)


Lesenswert?

Ich kann mir einfach nicht erklären Warum der XC18 Compiler hier diesen 
Fehler ausschreibt:



../../../Microchip/TCPIP Stack/UART.c:213:Error: syntax error

1
        void usart_write_P (const char *Buffer,...)
2
        {
3
4
        char str_buffer[10];
5
  char str_null_buffer[10];
6
  char move = 0;
7
  char Base = 0;
8
        int format_flag;
9
  int tmp = 0;
10
  char by;
11
  char *ptr;
12
13
        va_list ap;
14
  va_start (ap, Buffer);
15
16
  //Ausgabe der Zeichen
17
    for(;;)
18
  {
19
    by = Buffer++;
20
    if(by==0) break; // end of format string
21
22
    if (by == '%')
23
    {
24
                by = Buffer++;
25
      if (isdigit(by)>0)
26
        {
27
28
         str_null_buffer[0] = by;
29
        str_null_buffer[1] = '\0';
30
        move = atoi(str_null_buffer);
31
                by = Buffer++;
32
        }
33
34
      switch (by)
35
        {
36
                case 's':
37
                    ptr = va_arg(ap,char *);
38
                    while(*ptr) { putsUSART(*ptr++); }
39
                    break;
40
        case 'b':
41
          Base = 2;
42
          goto ConversionLoop;
43
        case 'c':
44
          //Int to char
45
          format_flag = va_arg(ap,int);
46
          putsUSART(format_flag++);
47
          break;
48
        case 'i':
49
          Base = 10;
50
          goto ConversionLoop;
51
        case 'o':
52
          Base = 8;
53
          goto ConversionLoop;
54
        case 'x':
55
          Base = 16;
56
          ConversionLoop:
57
58
          itoa(va_arg(ap,int),str_buffer,Base);
59
60
          int b = 0;    // <---------- Zeile 213 
61
62
          while (str_buffer[b++] != 0){};
63
          b--;
64
          if (b<move)
65
            {
66
            move -=b;
67
            for (tmp = 0;tmp<move;tmp++)
68
              {
69
              str_null_buffer[tmp] = '0';
70
              }
71
            //tmp ++;
72
            str_null_buffer[tmp] = '\0';
73
            strcat(str_null_buffer,str_buffer);
74
            strcpy(str_buffer,str_null_buffer);
75
            }
76
          putsUSART(str_buffer);
77
          move =0;
78
          break;
79
        }
80
81
      }
82
    else
83
    {
84
      putsUSART( by );
85
    }
86
  }
87
  va_end(ap);
88
}

von na (Gast)


Lesenswert?

Vermutlich erlaubt der Compiler es nicht ohne weiteres, in einem 
switch/case-Konstrukt Variablen zu definieren:

Probier mal, entweder i vorher zu definieren oder um die ganzen 
Anweisungen {} zu setzen:
1
       case 'x':
2
       {
3
          Base = 16;
4
          ConversionLoop:
5
6
          itoa(va_arg(ap,int),str_buffer,Base);
7
8
          int b = 0;    // <---------- Zeile 213 
9
10
          while (str_buffer[b++] != 0){};
11
          b--;
12
          if (b<move)
13
            {
14
            move -=b;
15
            for (tmp = 0;tmp<move;tmp++)
16
              {
17
              str_null_buffer[tmp] = '0';
18
              }
19
            //tmp ++;
20
            str_null_buffer[tmp] = '\0';
21
            strcat(str_null_buffer,str_buffer);
22
            strcpy(str_buffer,str_null_buffer);
23
            }
24
          putsUSART(str_buffer);
25
          move =0;
26
          }
27
          break;

von Tom M. (Gast)


Lesenswert?

simon schrieb:
> void usart_write_P (const char *Buffer,...)
> ...
> Aufruf mit:
> usart_write_P("receive: %i \n", (int) u);

Der Aufruf passt nicht zum Prototypen. usart_write_P erwartet einen 
Zeiger auf Characters, nicht einen int. Was versuchst du hier zu tun?

von simon (Gast)


Lesenswert?

Ich habe mal die ConversionLoop ganz auskommentiert.

Nun klagt er über

UART.c:202:Warning [2054] suspicious pointer conversion

1
void putsUSART( char *data) {
2
3
}
4
5
6
   void usart_write_P (const char *Buffer,...)
7
        {
8
        int format_flag;
9
10
11
12
           case 'c':
13
          //Int to char
14
          format_flag = va_arg(ap,int);
15
          putsUSART(format_flag++);  // <___ Fehler
16
          break;


Also wir halten mal fest, der code hat auf einem ATxmega bestens 
funktioniert.

Nur was ich mich nun Frage va_arg Liefert doch ganz klar ein integer 
zurück.
Der Integer wird mit format_flag++ um eins erhöht (ist aber kein 
Pointer)
putsUSART erwartet ein char pointer.

kann ich hier nun einfach casten mit
1
 putsUSART (  ( char *)format_flag++  ); ?

von simon (Gast)


Lesenswert?

Tom M. schrieb:
>> void usart_write_P (const char *Buffer,...)
>> ...
>> Aufruf mit:
>> usart_write_P("receive: %i \n", (int) u);
>
> Der Aufruf passt nicht zum Prototypen. usart_write_P erwartet einen
> Zeiger auf Characters, nicht einen int. Was versuchst du hier zu tun?


der *Buffer ist das "receive: %i \n" danach folgt (int) u was ein 
weiterer Parameter der funktion ist.

von simon (Gast)


Lesenswert?

also ich es scheint so als "na" recht hatte,

er erlaubt mir keine Variablen inerhalb von switch zu definieren.


Und ito weicht zwischen GCC und XC18 auch ab

GCC:
char *itoa (int __val, char *__s, int __radix)

XC18:
char *itoa (auto int value, auto char *s);


es gibt da kein radix.

von simon (Gast)


Lesenswert?

Gibt es da beim XC18 irgend eine Standard Funktion um ein byte
umzuwandeln in ein string der den hex wert enthällt?


BYTE b = 255;

sooo mir in einen string 0xFF schreiben.

von Fabian O. (xfr)


Lesenswert?

Warum nimmst Du nicht einfach das fertige printf()? Brauchst Du wirklich 
die paar Byte Programmspeicher, die Du mit der Selbstbauvariante ggf. 
sparst? Mir wärs das nicht wert ...

von simon (Gast)


Lesenswert?

eh ja, ich würde natuerlich auch sprintf oder printf nehmen wenn ich das 
mit meiner UART funktion verwenden kann

von simon (Gast)


Lesenswert?

1
#include <stdio.h> /* for sprintf, printf */
2
int main(void)
3
{
4
char sbuf[100], s[]="Print this string";
5
int x = 1, y;
6
char a = '\n';
7
8
9
y = sprintf(sbuf, "%s %d time%c", s, x, a);
10
11
12
printf("Number of characters printed to "
13
"string buffer = %d\n", y);
14
printf("String = %s\n", sbuf);
15
}

Ansich könnte ich doch hier auch einfach sbuf nehmen, das ist doch ein 
pointer auf char oder liege ich da falsch?

von Karl H. (kbuchegg)


Lesenswert?

Na offenbar hast du ja ein

         putsUSART(str_buffer);

zur Verfügung.

Also:

void putiUSART( int i )
{
  char buffer[10];
  itoa( buffer, i );    // weil dein itoa ja kein radix Argument hat
  putsUSART( buffer );
}

oder

void putiUSART( int i )
{
  char buffer[10];
  sprintf( buffer, "%d", i );
  putsUSART( buffer );
}


das sollte es wohl fürs erste tun.


Edit: Argh. WEnn man keine Tippfehler machen würde. Arrays werden 
natürlich mit [ ] geschrieben und nicht mit ( )

von simon (Gast)


Lesenswert?

Danke dir!

Das funzt... kein wunder warum Microchip keine funktionen dafür hatte, 
weil sprintf das ganze abdeckt was ich wollte.

von Fabian O. (xfr)


Lesenswert?

simon schrieb:
> eh ja, ich würde natuerlich auch sprintf oder printf nehmen wenn ich das
> mit meiner UART funktion verwenden kann

Du brauchst nur eine Funktion, die ein einzelnes Zeichen per UART 
ausgibt:
1
int uart_putchar(char c, FILE* stream)
2
{
3
  return putcUSART(c);
4
}

Die registrierst Du als Ausgabefunktion eines FILEs. Beim AVR 
funktioniert das so:
1
FILE uart_stdio = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

Über dieses FILE kannst Du jetzt Ausgaben per UART schreiben.
1
fprintf(&uart_stdio, "Hallo Welt\n");

Du kannst das FILE auch als Standardausgabe festlegen:
1
stdout = &uart_stdio;

Dann reicht für UART-Ausgaben einfach:
1
printf("Hallo Welt\n");

Du müsstest nur nachschauen, wie man bei Deinem Compiler einen 
Ausgabestream so initialisiert, so dass die UART-Ausgabefunktion genutzt 
wird.

von Bronco (Gast)


Lesenswert?

Um Deine ursprüngliche Frage zu beantworten:

simon schrieb:
> wieso kann man hier mit by==0 abfragen ob der Buffer zu Ende ist?
> würde das nicht zu einem Problem führen wenn u == 0?

Die Funktion
1
void usart_write_P (const char *Buffer,...)
ist eine Funktion mit variablen Argumenten ("VarArgs"), zu erkennen an 
dem "..." als Argument(enliste).

In einer solchen Funktion wird mithilfe von "stdarg.h" die variable 
Liste von Argumenten abgearbeitet.

Dein Code-Ausschnitt
1
  by = pgm_read_byte(Buffer++);
2
    if(by==0) break; // end of format string
bezieht sich nun einzig und allein auf den String, den Du in "buffer" 
übergeben hast, aber keineswegs auf die weiteren Argumente.

Das heißt
1
usart_write_P("receive: %i \n", (int) u);
übergibt in "buffer" den String "receive: %i \n", welcher mit dem 
impliziten Character 0x00 abgeschlossen ist.
Die Bedingung
1
    if(by==0)
wird also wahr, wenn dieses implizite 0x00 erreicht wird.

Was die Funktion aber mit den anderen Argumenten anfängt, hat damit gar 
nichts zu tun.

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.