Problem mit String und Pointer

Gast #1581146
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 =)
Gast #1581158
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?
Gast #1581162
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.
#1581166
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.
#1581547
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.
#1581911
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.
#1582172
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.
#1582213
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.
#1582250
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*
#1582505
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
#1583078
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.
Persönliche Seite #1583100
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.
Gast #1583120
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
Gast #1584624
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.
#1584650
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.

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