Forum: Compiler & IDEs Ein Stringproblem


von Hemi 8. (hemi850)


Lesenswert?

Hallo Zusammen,

ich versuche gerade ein String zusammen zu bauen:

Hier die Funktion:
1
// Eine Nachricht zusammenbauen:
2
char build_ibus_message ( char Sender, char Receiver, char Message) {
3
  unsigned char ibus_message[127]  ;
4
  unsigned char length = 0;
5
6
  length = strlen (Message);
7
8
  strcpy (ibus_message, Sender);
9
  strcat (ibus_message, length);
10
  strcat (ibus_message, Receiver);
11
  strcat (ibus_message, Message);
12
13
  return ibus_message;
14
}

Sender, Receiver und Message sind jeweils ein "array of chars".

Mein Compiler sagt mir dann:
1
../help_funcs.h: In function 'build_ibus_message':
2
../help_funcs.h:8: warning: passing argument 1 of 'strlen' makes pointer from integer without a cast
3
../help_funcs.h:10: warning: pointer targets in passing argument 1 of 'strcpy' differ in signedness
4
../help_funcs.h:10: warning: passing argument 2 of 'strcpy' makes pointer from integer without a cast
5
../help_funcs.h:11: warning: pointer targets in passing argument 1 of 'strcat' differ in signedness
6
../help_funcs.h:11: warning: passing argument 2 of 'strcat' makes pointer from integer without a cast
7
../help_funcs.h:12: warning: pointer targets in passing argument 1 of 'strcat' differ in signedness
8
../help_funcs.h:12: warning: passing argument 2 of 'strcat' makes pointer from integer without a cast
9
../help_funcs.h:13: warning: pointer targets in passing argument 1 of 'strcat' differ in signedness
10
../help_funcs.h:13: warning: passing argument 2 of 'strcat' makes pointer from integer without a cast
11
../help_funcs.h:15: warning: return makes integer from pointer without a cast
12
../help_funcs.h:15: warning: function returns address of local variable

Was will er mir damit sagen?

ich stehe auf dem Schlauch.

Danke schonmal.

Grüsse
Heinrich

von daniel (Gast)


Lesenswert?

Moin,

du solltest die Typen der Parameter in char*
ändern.

Gruß
Daniel

von holger (Gast)


Lesenswert?

char build_ibus_message ( char *Sender, char *Receiver, char *Message) {

von Johannes M. (johnny-m)


Lesenswert?

Heinrich Geiger wrote:
> char build_ibus_message ( char Sender, char Receiver, char Message) {
> [...]
> Sender, Receiver und Message sind jeweils ein "array of chars".
Das ist doch schon gelogen! Alle drei Variablen sind schlicht char, nix 
Array. Wenn Du Arrays übergeben willst, dann musst Du schon Zeiger auf 
char als Parameter benutzen...

Außerdem ist ibus_message vom Typ unsigned char , die Funktionen 
wollen aber char sehen, weshalb der Compiler zu Recht meckert, dass es 
Vorzeichenkonflikte gibt.

von daniel (Gast)


Lesenswert?

Außerdem gibt es da noch ein Problem:

der Rückgabewert sollte wohl auch ein zeiger auf eine
Zeichenkette sein (char*).

In deinem Fall ist ibus_message aber ein lokales Array.
Wenn du einen Zeiger auf dieses Objekt zurückgibst, wird
der Zeiger ungültig, sobald die Funktion verlassen wird.

Verwende stattdessen ein lokales, als 'static' markiertes Array oder
gar eine globale Variable, auch wenn es nicht schön ist.


Zudem verwendest du unsigned char und char durcheinander.

Gruß
Daniel

von holger (Gast)


Lesenswert?

>  unsigned char ibus_message[127]  ;

Ein static könnte da auch nicht schaden.
Sonst ist der Inhalt von ibus_message[]
ganz schnell im Eimer.

von Rolf Magnus (Gast)


Lesenswert?

Mit

> warning: passing argument 1 of 'strlen' makes pointer from integer
> without a cast

will dir der Compiler sagen, daß strlen einen Zeiger erwartet, du ihm 
aber einen Integer übergibst (char ist ein Integertyp).


Und mit

> warning: pointer targets in passing argument 1 of 'strcpy' differ in
> signedness

will er dir sagen, daß ein ibus_message nicht, wie von strcpy verlangt, 
ein Array aus char, sondern ein Array aus unsigned char ist.

von holger (Gast)


Lesenswert?

Das wird wahrscheinlich auch nicht funktionieren:

  unsigned char length = 0;
  length = strlen (Message);

  strcat (ibus_message, length);

von Hemi 8. (hemi850)


Lesenswert?

So, es funzt:
1
char ibus_message[127];
2
3
// Eine Nachricht zusammenbauen:
4
void build_ibus_message ( char *Sender, char *Receiver, char *Message) {
5
  
6
  char length = 0;
7
8
  length = strlen (Message);
9
10
  strcpy (ibus_message, Sender);
11
  strcat (ibus_message, &length);
12
  strcat (ibus_message, Receiver);
13
  strcat (ibus_message, Message);
14
}

Danke & Grüsse
Heinrich

von holger (Gast)


Lesenswert?

Die Zeile ist immer noch faul

  strcat (ibus_message, &length);

length ist kein String. strcat kann unter Umständen
einmal quer durch den Speicher jagen und alles was nicht 0 ist
an ibus_message[] anfügen. Da die Größe von ibus_message[]
nicht berücksichtigt wird sogar darüber hinaus. Und dann wird
es richtig nett.

von Hemi 8. (hemi850)


Lesenswert?

Wie kann ich es dann besser machen?

Danke.

von daniel (Gast)


Lesenswert?

Ein Integer-Typ (int, aber auch char) ist eine Zahl - was du brauchst 
ist
eine Zeichenkette (zeiger auf ein char array), die die Darstellung der 
Zahl enthält.

Wenn dir die Funktion itoa() zur verfügung steht,
kannst du sie verwenden, um eine Zahl in eine Zeichenkette
umzuwandeln.
1
...
2
/* Du musst sicher sein, dass nie Zahlen umgewandelt werden, die
3
mehr als 16 Stellen haben. Das sollte bei 32-bit immer gegeben sein. */
4
#define MAX_NUMBER_STR_LEN 16
5
/* Am besten keine absoluten Zahlen mitten im Code.
6
Das würde die Wartbarkeit verringern. */
7
#define IBUS_MSG_LEN       128
8
char ibus_message[IBUS_MSG_LEN];
9
...
10
// Eine Nachricht zusammenbauen:
11
void build_ibus_message( char *Sender, char *Receiver, char *Message)
12
{
13
  size_t length = 0;
14
  char lenStrBuf[MAX_NUMBER_STR_LEN];
15
16
  length = strlen (Message);
17
18
  /* Basis=10 -> Dezimaldarstellung */
19
  /* Basis=16 -> Hexadezimaldearstellung */
20
  itoa(length, lenStrBuf, 10);
21
22
  strncpy (ibus_message, Sender, IBUS_MSG_LEN);
23
  strncat (ibus_message, lenStrBuf, IBUS_MSG_LEN);
24
  strncat (ibus_message, Receiver, IBUS_MSG_LEN);
25
  strncat (ibus_message, Message, IBUS_MSG_LEN);
26
  return;  
27
}

Beachte bitte:
- strncpy, strncat statt strcpy, strcat
  Die maximale Länge von ibus_message wird geprüft.
  -> Sicherheit vor Speicherüberläufen
  Daumenregel: Nie die Varianten ohne 'n' verwenden!
- Wenn build_ibus_message ein zweites mal aufgerufen wird,
  wird die erste message überschrieben.

Sauber und sicher kannst du build_ibus_message so verwenden:
1
void any_function_name(void)
2
{ 
3
  ...
4
  char myMsg1[IBUS_MSG_LEN];
5
  char myMsg2[IBUS_MSG_LEN];
6
  ...
7
  build_ibus_message(...);
8
  strncpy(myMsg1, ibus_message, IBUS_MSG_LEN);
9
  build_ibus_message(...);
10
  strncpy(myMsg2, ibus_message, IBUS_MSG_LEN);
11
  ...
12
}
Gruß
Daniel

von Hemi 8. (hemi850)


Lesenswert?

Hallo Daniel,

vielen Dank für Deine ausführliche Antwort. Danke.

Ich habe in der Zwischenzeit es versucht so zu lösen:
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <string.h>
4
5
struct transfer {
6
  char sender;
7
  char length;
8
  char receiver;
9
  char message[9];
10
  char xor;
11
};
12
13
14
struct transfer transfer;
15
16
int main ( void ) {
17
18
  char msg[] = {0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
19
  int i;
20
21
  transfer.sender = 0x02;
22
  transfer.length = strlen (msg)+2;
23
  transfer.receiver = 0x01;
24
  
25
  memcpy (transfer.message, msg, sizeof(msg));
26
27
  transfer.xor = 0;  
28
29
  printf ("Länge %X\n", transfer.length);
30
  
31
  transfer.xor ^= transfer.sender;
32
  transfer.xor ^= transfer.length;
33
  transfer.xor ^= transfer.receiver;
34
35
  for (i=0; i<sizeof(msg); i++) {
36
    transfer.xor = transfer.xor ^ msg[i];
37
  }
38
  
39
  
40
  printf ("XOR: %X\n", transfer.xor);
41
42
  printf ("Sender: %X, Länge: %X, Empfänger: %X, Daten: %X, CRC: %X\n", transfer.sender, transfer.length, transfer.receiver, transfer.message[0], transfer.xor);
43
44
45
  return 0;
46
}

Diese Funktion hat aber npaar Probleme:

1. Strlen ist zwar schön und gut, aber es bricht ab, sobald sie ein 0x00 
"sieht", weil das bedeutet für sie Stringende. In meinem Fall ist aber 
ein 0x00 zulässig.

Das würde bedeuten, dass ich immer wissen muss, wie lange meine 
Netzdaten sind, dann kann ich sauber arbeiten.

Das Gleiche gilt auch für SizeOf, so viel ich weiss.

Alle Daten sind dexadzimal, nicht dezimal.

Hier mal ein Beispiel von einer Nachricht:
1
char nachricht = {0x02, 0x0B, 0x01, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6};

0x02 ist mein Sender (1 Byte lang)
0x0B ist die Länge ( also 11 Byte), Länge an sich ist auch ein Byte
0x01 ist mein Empfänger (1 Byte lang)
0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF sind meine 
Nutzdaten (in diesem Fall 9 Byte von 32 möglichen)
0xB6 ist XOR-CRC (1 Byte)

Die Länge wird über Nutzdaten + Empfänger + XOR CRC ausgerechnet.
XOR wird über die gesamte Nachricht ausgerechnet.

Das Problem, was ich noch habe, dass ich die transfer.message nicht 
dynamisch machen kann, da ich nicht weiss, wie lang der String sein 
soll. Bzw. es ist von Fall zu Fall unterschiedlich. Deswegen muss ich 
die Länge der Nutzdaten vor dem Bau der Nachricht schon wissen, was aber 
kein Problem ist.

Grüsse
Heinrich

von daniel (Gast)


Lesenswert?

Moin Heinrich,

bitte durchdenk' mal die folgenden Fragen/Anmerkungen,
heute abend/nacht werde ich noch mal reinschauen,
jetzt muss ich erstmal weg.

- brauchst du build_ibus_message() dann gar nicht mehr?
  oder soll der o.g. code das ersetzen?
- sizeof() und strlen() sind grundverschieden, bitte nachschlagen!
- Bei der Deklaration von transfer.message verwendest du 9 und nicht 32.
- Wenn es kein Problem ist, dass du die Länge der Nutzdaten vorher 
kennst,
  was ist dann dein Problem? Setz' die arraygröße von transfer.message
  auf das maximum (32) und verwende die bekannte message-Größe als 
parameter für memcpy().
- mit printf("%X", transfer.message[0]); gibst du nur das erste Zeichen 
der Msg aus.

Ansonsten ist der Code doch brauchbar:

Vorschlag:
1
#define HEADER_LEN   2 // receiver + xor
2
#define MAX_PAYLOAD_LEN  32 
3
#define MAX_IBUS_MSG_LEN (MAX_PAYLOAD_LEN+HEADER_LEN)
4
char ibus_msg[MAX_IBUS_MSG_LEN];
5
// Gibt die Gesamtlänge zurück
6
unsigned char build_msg(struct transfer *t)
7
{
8
  unsinged char i = 0, j;
9
  if (!t) return;
10
  memset(ibus_msg, 0, MAX_IBUS_MSG_LEN);
11
  ibus_msg[i++] = t->sender;
12
  ibus_msg[i++] = t->total_length;
13
  ibus_msg[i++] = t->receiver;
14
  memcpy(&(ibus_msg[i]), t->payload, t->payload_length);
15
  i += t->payload_length;
16
  ibus_msg[i++] = t->xor;
17
  return i;
18
}

struct transfer musst du dann anpassen und ausfüllen.

Gruß
Daniel

von Hemi 8. (hemi850)


Lesenswert?

Hallo Daniel,

danke erstmal.

zum Punkt 1: Doch diese Funktion brauche ich nach wie vor. Ich mache mir 
immer so kleine Programmchen, mit denen ich es dann austeste und diese 
dann in das Programm einbaue. Also es wäre dann Ersatz.

zum Punkt 2: Stimmt, sizeof liefern die reservierte Grösse zurück und 
strlen die Länge eines Strings. Hast Recht.

Zum Punkt 3: Ja, das habe ich testweise runtergesetzt. Es hat den 
Hintergrund, dass nicht immer alle 32 Byte belegt werden, aber dann alle 
32 Byte verschickt werden, wenn man die Grösse so belässt.

Zum Punkt 4: Ja, die Länge der Nachricht weiss ich schon vorher. Das 
heisst, wenn ich zum Beispiel Nutzdaten als "92 95 83" habe, dann weiss 
ich ja, dass diese Geschichte ja nur 3 Byte lang ist, dazu kommt noch 1 
Byte für Empfänger und 1 Byte für CRC, ergibt also 5 Byte. Diese 5 Byte 
kann ich dann schon mal reinschreiben als Länge.

Zum Punkt 5: Ja, das weiss ich, war testweise geändert.

Ich glaube, ich bohre einfach meine Sendenfunktion so weit auf, dass ich 
diese Parameter an sie übergebe und sie dann die ganzen Daten 
rausschickt und dann am Ende die XOR CRC ausrechnet. Ich denke, das wäre 
das Einfachste.

Oder wie siehst Du das?

Danke & Grüsse
Heinrich

von Daniel (Gast)


Lesenswert?

Ja, ich denke auch, dass deine Sendefunktion das ganz gut
komplett erledigen kann. So kompliziert ist es ja nicht mehr,
wenn du die erforderlichen Parameter ohnehin im Voraus kennst.

Gruß
Daniel

von Hemi 8. (hemi850)


Lesenswert?

Ich wollte halt eine "generische" Funktion haben, die mir die 
Nachrichten zusammenbaut. Aber das ist ja eigentlich nicht erforderlich, 
da man sie beim Bauen ja auch gleich rauschicken kann.

Trotzdem vielen Dank.

Grüsse
Heinrich.

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.