Forum: Mikrocontroller und Digitale Elektronik Problem mit String und Pointer


von Ralf (Gast)


Lesenswert?

Hallo!

Ich habe ein Problem beim Einlesen von SMS aus meinem TC35i Modem. Wo 
die Daten herkommen ist eigentlich egal, das Problem liegt nämlich ganz 
wo anderst.
Mein Code sieht folgendermaßen aus:

Hier wird das SMS ausgelesen (bzw mehrere) und in ein 721 Char breites 
Array (sms_buffer[721])geschrieben. An der letzten Stelle steht '\0' um 
den String abzuschließen - standard.
1
   gsm_read_sms();

Die Daten stehen nun im Array. Ich habe ein Unterprogramm, welches die 
Daten verarbeitet, in dieses Unterprogramm wird ein String übergeben 
(sBase64_roh).

Also schreibe ich die Startadresse des Arrays auf *sBase64_roh und 
übergebe diese.
In dem unten angeführten Beispiel wird sie nicht übergeben, sondern über 
USART an den PC geschickt (zum Debuggen).
1
    
2
3
  char *sBase64_roh;
4
  char sms_buffer[721];
5
6
  sBase64_roh = &sms_buffer[0];
7
8
  Uart_Puts("AUSGABE DES ROH TEXTES: ");
9
  Uart_Puts(sBase64_roh);

Die Situation ist folgende: Der Controller sendet die ganze Zeit 
"AUSGABE DES ROH TEXTES: ". Mehr nicht, er scheint mit dem 
"Uart_Puts(sBase64_roh);" offensichtlich nicht klarzukommen. Oder wo 
könnte sonst der Hund begraben sein?

Danke für die Hilfe =)

von Loonix (Gast)


Lesenswert?

Du übergibst die Adresse, nicht den Pointer.
1
   Uart_Puts(*sBase64_roh);

sollte funktionieren


Grüße

von Loonix (Gast)


Lesenswert?

Die oben von mir gewählte Ausdrucksweise ist nicht ganz richtig. Der 
Pointer ist ja eine Adresse, aber ohne das * wird die Variable einfach 
als numerischer Wert verarbeitet, nicht als Pointer.

Stimmts?

von P. S. (Gast)


Lesenswert?

Totales Chaos. Du uebergibst einen Zeiger auf char, was man gemeinhin 
"String" nennt. Und du rufst eine Funktion auf, die einen String 
erwartet um ihn ueber die serielle Schnittstelle zu senden. Nur ist der 
String nicht initialisiert, mit etwas Glueck ist also schon das erste 
Zeichen 0 und du siehst - nix. Wenn du die Adresse lesbar verschicken 
willst, wirst du sie nach Ascii formatieren muessen.

von Tim S. (maxxie)


Lesenswert?

Du hast keinen Inhalt im sms_buffer[] (==sBase64_roh) in deinem 
Codeschnippsel. Es ist, wenn wie gezeigt verwendet, mit dem gefüllt, was 
zufällig im Stack steht.

Meist nichts druckbares. Oft auch mal eine 0, die das Ende des Strings 
bedeutet.
Daher ist die Ausgabe die du angibst Plausibel.

von Tim S. (maxxie)


Lesenswert?

Leute, die Casts sind in Ordnung, wenn auch unnötig.

char chArray[] ;
und
char *chPointer ;

sind Variablen mit äquivalenten Datenetypen. (Bis auf das Treatment von 
Warnings)

von P. S. (Gast)


Lesenswert?

Tim Seidel schrieb:
> Leute, die Casts sind in Ordnung, wenn auch unnötig.

Welche Casts?

von Tim S. (maxxie)


Lesenswert?

1
char *sBase64_roh;
2
char sms_buffer[721];
3
4
sBase64_roh = &sms_buffer[0];
5
6
Uart_Puts(sBase64_roh);

Die 3(4?) Impliziten hier.

char[] zu char& zu char *
und das ?:
char *
zu const char *

Der eine Implizite in
1
Uart_Puts(sms_buffer);
hätte ausgereicht.

von Karl H. (kbuchegg)


Lesenswert?

Tim Seidel schrieb:
>
1
> char *sBase64_roh;
2
> char sms_buffer[721];
3
> 
4
> sBase64_roh = &sms_buffer[0];
5
> 
6
> Uart_Puts(sBase64_roh);
7
>
>
> Die 3(4?) Impliziten hier.

Da gibt es keinen implizite Casts.
Alle Datentypen passen perfekt zusammen.

> char[] zu char& zu char *

Den Cast gibt es in C gar nicht.
Und da an dieser Stelle char[] nichts anderes als eine
andere Schreibweise für char* ist, ist auch sofort ersichtlich,
dass es diesen cast, wenn es ihn gäbe, gar nicht braucht.

> sBase64_roh = &sms_buffer[0];

sms_buffer         ist ein Array von char
sms_buffer[0]      ist ein einzelnes Element aus diesem Array,
                   hat also den Datentyp char
&sms_buffer[0]     Wendet man den Address Operator auf einen char an
                   erhält man selbstverständlich einen char*

sBase64_roh = &sms_buffer[0];    links vom = ist der Datentyp char *
                                 rechts vom = ist der Datentyp char *

Also, warum soll da irgendetwas gecastet werden?

> und das ?:
> char *
> zu const char *

Das ist kein Cast.
In die umgekehrte Richtung wäre es einer.
Aber so rum passiert nichts, weil keine Notwendigkeit dazu besteht.

const ist die Zusicherung, nichts zu verändern.
Wenn dir dein Kumpel zusichert, in ein geliehenes Buch nichts 
hinzuschreiben, kannst du ihm bedenkenlos deine wertvolle 
Guthenberg-Bibel geben. Selbst wenn man in die prinzipiell etwas 
hineinschreiben könnte (sie also nicht const ist), dein Kumpel behandelt 
sie ja als nicht-beschreibbar (const)

Erst im umgekehrten Fall musst du dir Sorgen machen:
Deine Bibel ist const (also als nicht-beschreibbar anzusehen) und dein 
Kumpel gibt dir bei der Übernahme nicht die Zusicherung, dieses const zu 
respektieren.
Dann musst du dir überlegen, inwieweit du deinem Kumpel traust, und das 
const für den Zeitraum des Ausleihens wegcastest.

> Der eine Implizite in
>
1
> Uart_Puts(sms_buffer);
2
>
> hätte ausgereicht.

Wenn wir mal eine übliche Def. voraussetzen
void Uart_Puts( const char* string )
dann wird auch hier nichts implizit gecastet.
Die Initialisierung einer const Variablen mit einem Wert erfordert 
keinen Cast, wenn der restlichen Datentypen übereinstimmt. Die Variable 
legt sich stärkere Restriktionen auf, was mit ihr möglich ist. Das 
tangiert aber nicht die Quelle des Wertes und erfordert auch keinerlei 
Aktionen bei der Zuweisung.
Erst umgekehrt, wenn die Quelle über Restriktionen verfügt, die das Ziel 
nicht gewillt ist einzuhalten (oder zumindest keine Zusage dafür 
abgibt), sind Aktionen (wie zb ein Cast) notwendig.

von Loonix (Gast)


Lesenswert?

@kbuchegg

Wirklich schön verständlich, deine Erklärungen. Danke dafür!
(Sollte auch mal gesagt werden)

Wäre interessant ob es dem TE auch weitergeholfen hat?

von Karl H. (kbuchegg)


Lesenswert?

Loonix schrieb:

> Wäre interessant ob es dem TE auch weitergeholfen hat?

Dazu müsste man erst mal wissen, was er eigentlich machen will.
Will er den String an sich ausgeben, oder will er den numerischen Wert 
der Adresse, an der der String gespeichert ist, wissen (wozu auch 
immer).

Im ersten Fall, stimmt das schon so wie er das hat. Jedoch ist der 
eigentliche String entweder nicht initialisiert oder es ist ganz einfach 
ein Leerstring.

Im zweiten Fall, müsste er den numerischen Wert des Pointers erst mal 
mit zb ltoa (wenn sizeof(long) == sizeof(void*)) oder sprintf selbst in 
einen String umwandeln lassen, um den dann mittels Uart_Puts auszugeben.

von Tim S. (maxxie)


Lesenswert?

>> char[] zu char& zu char *
>
> Den Cast gibt es in C gar nicht.

Achso. Dann ist die ANSI-C Spec falsch:
> If the unary * operator is applied to this
> pointer explicitly, or implicitly as a result of subscripting, the
> result is the pointed-to ( n -1)-dimensional array, which itself is
> converted into a pointer if used as other than an lvalue.

> The array-subscript
> [] and member-access .  and -> operators, the address & and
> indirection * unary operators, and pointer casts may be used in the
> creation an address constant, but the value of an object shall not be
> accessed by use of these operators.

Ob die Konversation nun irgendwelche Instruktionen benötigt oder ohne 
Zutun die Binärrepräsentation verwenden kann, ändert nichts daran, dass 
es eine Wandlung (Cast) des qualifizierten Datentyps ist.

Nach Ansi-C sind die beiden qualifizierten Typen const char und char 
nicht kompatibel.
Damit wird eine Wandlung (die aus Nichts ausser dem "Merken" des const 
allein durch den Compiler besteht) in beide Richtungen nötig,
denn die Kompatibilitäts-Relation:
> For two qualified types to be compatible, both shall have the
> identically qualified version of a compatible type; the order of type
> qualifiers within a list of specifiers or qualifiers does not affect
> the specified type.
ist offensichtlich symetrisch.

von Karl H. (kbuchegg)


Lesenswert?

Tim Seidel schrieb:
>>> char[] zu char& zu char *
>>
>> Den Cast gibt es in C gar nicht.
>
> Achso. Dann ist die ANSI-C Spec falsch:


Wo kommt in den ANSI-C Spec der Datentyp char& (also eine Referenz) vor?

> Nach Ansi-C sind die beiden qualifizierten Typen const char und char
> nicht kompatibel.

OK.
Trotzdem betreibst du hier Haarspalterei

(und wenn wir genau sind, haben wir von const char* und char* 
gesprochen. Und diese beiden Datentypen SIND per Definition kompatibel. 
Der C-Standard macht dafür extra eine Ausnahme :-)

Bei der Zuweisung eines int an einen long gibt es so gesehen dann auch 
einen 'impliziten cast', der allerdings nicht wirklich irgend jemanden 
auch nur im Geringsten interessiert. Und dort ändert sich unter 
Umständen sogar das Bitmuster.

von Karl H. (kbuchegg)


Lesenswert?

Tim Seidel schrieb:
>>> char[] zu char& zu char *
>>
>> Den Cast gibt es in C gar nicht.
>
> Achso. Dann ist die ANSI-C Spec falsch:
>> If the unary * operator is applied to this
>> pointer explicitly, or implicitly as a result of subscripting, the
>> result is the pointed-to ( n -1)-dimensional array, which itself is
>> converted into a pointer if used as other than an lvalue.
>


Hmm. Der Punkt gilt ja wohl bei
sBase64_roh = &sms_buffer[0];
nicht. Denn hier wird kein unary * operator angewendet, weder explizit 
noch implizit, denn der & operator und anwenden dieser Regel ...

>> The array-subscript
>> [] and member-access .  and -> operators, the address & and
>> indirection * unary operators, and pointer casts may be used in the
>> creation an address constant, but the value of an object shall not be
>> accessed by use of these operators.

... verbietet das. Da ist ausdrücklich davon die Rede, dass & den Wert 
nicht antatscht, dass es also bei der Auswertung von

    &sms_buffer[0]

zu keinem impliziten unary * (Dereferenzierung) kommt. Statt dessen 
steht da, dass eine "address constant" gebildet wird. Und eine "address 
constant", vulgo Pointer, hat meines Wissens nicht den Datentyp 
iregdnwas[] sondern irgendwas*

von Tim S. (maxxie)


Lesenswert?

Karl heinz Buchegger schrieb:
> Tim Seidel schrieb:
>>>> char[] zu char& zu char *
>>>
>>> Den Cast gibt es in C gar nicht.
>>
>> Achso. Dann ist die ANSI-C Spec falsch:
>>> If the unary * operator is applied to this
>>> pointer explicitly, or implicitly as a result of subscripting, the
>>> result is the pointed-to ( n -1)-dimensional array, which itself is
>>> converted into a pointer if used as other than an lvalue.
>>
>
>
> Hmm. Der Punkt gilt ja wohl bei
> sBase64_roh = &sms_buffer[0];
> nicht. Denn hier wird kein unary * operator angewendet, weder explizit
> noch implizit, denn der & operator und anwenden dieser Regel ...

Doch, das wird es.
sBase64_roh = &sms_buffer[0]; evaluiert zu
sBase64_roh = &(*(sms_buffer+(0)))

>
>>> The array-subscript
>>> [] and member-access .  and -> operators, the address & and
>>> indirection * unary operators, and pointer casts may be used in the
>>> creation an address constant, but the value of an object shall not be
>>> accessed by use of these operators.
>
> ... verbietet das. Da ist ausdrücklich davon die Rede, dass & den Wert
> nicht antatscht, dass es also bei der Auswertung von

Du missverstehst den Satz.

Was dort beschrieben wird ist z.B. die folgende Situation (absichtlich 
alles dabei):
1
char array[4] = { 1,2,3,4 } ;
2
u32 val = *(int *)&array[0] ;

Hier wird der Typ des Pointer gecastet. Der Wert jedoch wird nicht 
angetatstet (weder gelesen noch geschrieben)

val ist nach dem Satz oben das int an der Stelle von array (je nach 
endianess) und nicht (das ist die zentrale Aussage, neben der 
Seitenbemerkung, dass es sich bei subscriptions des ersten Quotes um 
Casts handelt) dass val = (int) 1 ist. (bei dem der Wert angefasst und 
erweiter worden wäre.


>     &sms_buffer[0]
>
> zu keinem impliziten unary * (Dereferenzierung) kommt. Statt dessen
> steht da, dass eine "address constant" gebildet wird. Und eine "address
> constant", vulgo Pointer, hat meines Wissens nicht den Datentyp
> iregdnwas[] sondern irgendwas*

>>> may be used in the
>>> creation an address constant

Da steht nicht, wie du hier behaupten willst. Schlüsselworte sind hier 
"may" und in vorderster front "in the creation". Genauer: a) Es muss 
nicht b) und es muss nicht in einem Schritt erledigt sein

Also kann und muss (um OBdA zu arbeiten) angenommen werden, dass jeder 
Schritt zur Adressenbildung auch durchgeführt wird.


PS: Das mit dem Haarespalten fing m.E. früher an. Ich lass mich ungern 
mit falschen Aussagen korrigieren. Insbesondere dann nicht, wenn diese 
falschen Aussagen von Accounts kommen, die eine besondere Verpflichtung 
zur Genauigkeit und gutem Umgangston haben.

Und das für die simple Aussage, dass die Typzuweisungen passen ... naja

von Karl H. (kbuchegg)


Lesenswert?

Tim Seidel schrieb:

> Und das für die simple Aussage, dass die Typzuweisungen passen ... naja

Genau das ist der springende Punkt
Wiellst du in Zukunft jede Zuweisung ala

 long i;
 i = 5;

mit 'die impliziten Casts sind ok' kommentieren?
Dein Aufbringen der Thematik Casting trägt in dieser Fragestellung 
nichts bei.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Hi,

teste mal:
1
char *sBase64_roh;
2
char sms_buffer[]="Hallo, Welt";
3
4
sBase64_roh = &sms_buffer[0];
5
6
Uart_Puts("AUSGABE DES ROH TEXTES: ");
7
Uart_Puts(sBase64_roh);

Dann siehst du, ob zumindest der Kram funzt (sollte). Ab wo beginnst du 
dein array zu füllen, ab [0] oder [1] ?
Falls erst bei [1], dann könnte in [0] eine 0 stehen, das wäre das Ende 
deines strings :-)

Noch ein Tipp: (s)printf liefert dir die Zahl der Zeichen zurück, damit 
kann man schöne Sachen machen wie:
1
char string[1024];
2
char *pString;
3
4
pString = string;
5
6
pString += sprintf(pString, "Hallo ");
7
pString += sprintf(pString, "Welt");
8
9
printf(string);

Anmerkung: Ev. die n-variante vom sprintf (snprintf) verwenden, auf die 
Gefahr eines Überlaufes hin.


VG,
/th.

von Jens (Gast)


Lesenswert?

Moin zusammen,

um die Sache mal von einer anderen Richtung anzugehen: Es ist nicht 
zufällig ein AVR-Prozessor und das leidige Problem mit Strings im RAM 
oder im Flash?

Denn die umfängliche Diskussion über cast verdeckt meiner Meinung nach, 
dass das Ausgangsprogramm eigentlich funktionieren müsste...

Gruß
Jens

von Random .. (thorstendb) Benutzerseite


Lesenswert?

muss man da nicht solche strings explizit ins ROM tackern mit PROGMEN ?

von Jens (Gast)


Lesenswert?

Hallo Random,

recht hast Du...Kopie im RAM...

Gruß
Jens

von us73 (Gast)


Lesenswert?

Ralf schrieb:
> char *sBase64_roh;
>   char sms_buffer[721];
>
>   sBase64_roh = &sms_buffer[0];
>
>   Uart_Puts("AUSGABE DES ROH TEXTES: ");
>   Uart_Puts(sBase64_roh);

Kann es nicht sein, dass die Zeile

>   Uart_Puts(sBase64_roh);

einfach gar nichts bewirkt, also keine Ausgabe erzeugt, weil sms_buffer 
keine sinnvoll ausgebbaren Zeichen enthält ?
Und Du daher nur die Ausgabe "AUSGABE DES ROH TEXTES: " siehst ?

Also, zum Test:
sms_buffer mit einem String initialisieren und dann wird Uart_Puts() 
auch diesen anzeigen. Dann gehts weiter.

von Tim S. (maxxie)


Lesenswert?

Karl heinz Buchegger schrieb:
> Tim Seidel schrieb:
>
>> Und das für die simple Aussage, dass die Typzuweisungen passen ... naja
>
> Genau das ist der springende Punkt
> Wiellst du in Zukunft jede Zuweisung ala
>
>  long i;
>  i = 5;
>
> mit 'die impliziten Casts sind ok' kommentieren?
> Dein Aufbringen der Thematik Casting trägt in dieser Fragestellung
> nichts bei.

Zumindest dann, wenn wie geschehen behauptet wird, dass die Zuweisung 
nicht in Ordnung ist.

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.