Abfrage ob Buffer zu ende ist.

Gast #3073331
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;
Gast #3073348
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
Gast #3073357
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
}
Gast #3073362
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;
Gast #3073390
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++  ); ?
Gast #3073395
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.
Gast #3073408
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.
Gast #3073717
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?
#3073722
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 ( )
#3073868
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.
Gast #3075219
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren