Problem mit Funktion: Pointer falsche Arraygröße

#1809028
Lesenswert?

Hallo Leute, ich hab mal wieder nen Hänger im Kopf und weis nicht warum.

Hier folgender Code:
1
void SIMKNX_wert_setzen(uint8_t objectnumber, unsigned char *value)
2
{
3
  int i;
4
  int j = 0;
5
  unsigned char kommando[(sizeof (value) ) + 6];
6
  USART_KESSEL_Transmit(sizeof (kommando)); //sollte eigentlich 10 sein, ist aber 8
7
  }
8
void SIMKNX_wert_senden(unsigned int value, unsigned int objectnumber, unsigned int length) // Wert, SIMKNX Objektnummer, Länge in byte
9
{
10

11
// Wert auf Objekt setzen: ovs(ObjNr) Wert
12

13
  if (length == 2)
14
  {
15
    unsigned char lengthvalue[4];
16
    lengthvalue[0] = length+1;
17
    lengthvalue[1] = ((value/2));  //Vorkommastelle
18
    lengthvalue[2] = 0x2C;      //,
19
    lengthvalue[3] = (value%2);  //Nachkommastelle
20
    
21
    USART_KESSEL_Transmit(sizeof (lengthvalue));  //Hier steht noch eine 4
22
    SIMKNX_wert_setzen(objectnumber, lengthvalue);

Warum ist in der Funktion SIMKNX_wert_setzen sizeof(value) nur noch 2?
Liegt ja bestimmt an dem Pointer.
Könntet ihr mich mal aufklären?
Falls ihr Vorschläge zur Verbesserung habt bin ich auch offen.
Gast #1809040
Lesenswert?

Beschreib mal genauer was du fabrizieren willst.
Das sind mir sehr nach Zeichenketten aus.
Allerdings musst du beim "Anhängen" von Zeichen sicherstellen, das der 
Speicherplatz nach dem String noch frei ist, sonst gibt es böse 
Laufzeitfehler.
:-)
#1809051
Lesenswert?

Ja da werden Zeichenketten gebaut:-)

Also folgendes SIMKNX_wert_senden bastellt den Wert der später gesendet 
werden soll, dieser ändert sich natürlich immer mal.
Dieser Wert wird dann mit SIMKNX_wert_setzen(objectnumber, lengthvalue);
in einen Befehl verpackt der dann später gesendet wird.
Hier mal der ganze Code von SIMKNX_wert_setzen:
1
void SIMKNX_wert_setzen(uint8_t objectnumber, unsigned char *value)
2
{
3
  int i;
4
  int j = 0;
5
  unsigned char kommando[(sizeof (value) ) + 6]; //sollte bei dem Beispiel 10 ergeben dann passt alles
6
  USART_KESSEL_Transmit(sizeof (kommando));
7
  kommando[0] = 0x6F; //O
8
  kommando[1] = 0x76; //v
9
  kommando[2] = 0x73; //s
10
  kommando[3] = 0x28; //(
11

12
  kommando[4] = objectnumber;
13
  kommando[5] = 0x29;
14
  for( i = 6; i < sizeof( kommando ) / sizeof( *kommando ); i++ )
15
      {
16

17
      kommando[i] = value[j];
18
      j++;
19
      }
20
  for( i = 0; i < sizeof( kommando ) / sizeof( *kommando ); i++ )
21
    {
22
      SIMKNX_Transmit(kommando[i]);
23
    }
24
}
Gast #1809058
Lesenswert?

2 Möglichkeiten:

1. die Länge des Feldes als PArameter mitübergeben

2. die übergebene Zeichenkette mit einem Nullbyte terminieren, um in der 
Funktion die Länge ermitteln zu können.

Was davon besser ist, darfst du entscheiden :-)
Gast #1809068
Lesenswert?

dann schreib doch auch
1
  kommando[0] = 'O'; 
2
  kommando[1] = 'v'; 
3
  kommando[2] = 's'; 
4
  kommando[3] = '('; 
5
  kommando[4] = objectnumber;
6
  kommando[5] = ')';

sizeof wird zu gern verwendet .. ist aber ein präprozessoraufruf ..
nachem kompilieren is das wech ..
bzw stehen da zahlen ..

anhand des pointers bekommst du die länge nicht raus ...

dynamischer speicherbereich ist schön .. auf einem AVR ist so ein 
aufwnad meist aber eher negaiv ..
warum nicht e8infach ein festes array ...
die 10 byte für das array auf dem stack machen den kohl nicht fetter
Gast #1809075
Lesenswert?

Die Ursache liegt in der Dir fehlenden Differenzierung zwischen Vektor 
und Zeiger. Ihr ist in K&R, ein ganzes Kapitel gewidmet, das Du mal 
lesen solltest, ebenso wie die Beschreibung von sizeof dort.

In main ist lengthvalue ein Vektor, was als Argument von sizeof eben die 
definierte Länge des Vektors ergibt. In der Funktion allerdings hast Du 
aus dem Vektor einen Zeiger auf char gemacht, dessen Grösse sizeof 
korrekt als Grösse des Zeigers angibt, nicht des Vektors. Die 
Information, ob und wieviele chars denn auf den ersten folgen, ist 
verlorengegangen.

sizeof, angewendet auf Vektoren, wertet zur Compile-Zeit, nur die 
definierten Längen dieser Vektoren aus, also die in der eckigen Klammer 
ausdrücklich angegebene Länge.

Es ist, nach oberflächlichem Studium, verführerisch, anzunehmen, das 
sizeof ein bequemer Ersatz für strlen ist, mit dem man zur Compile-Zeit 
sowohl Vektor- als auch String-Längen ermitteln kann, weil zwischen 
diesen kein wesentlicher Unterschied zu bestehen scheint. Dem ist aber 
nicht grundsätzlich so.
Das gilt auch, obwohl einige Unterschiede nur deswegen gültig zu sein 
scheinen, weil sie definiert worden sind, aber intuitiv kein 
funktionaler Grund zur Definition dieses Unterschieds vorzuliegen 
scheint.

So könnte man unterstellen, das der Compiler wissen müsste, das ein 
Zeiger auf einen Vektor auf einen Speicherbereich mit der Länge des 
ursprünglichen Vektors verweist. Aber dann bliebe die Frage, wie man mit 
sizeof die Länge eines Zeigers auf einen String ermittelt, bzw. eine 
Ungleicheit in der Behandlung von Zeigern auf Vektoren im Gegensatz zu 
andere Typen.
So aber, in dem man die einmal festgesetzte Unterscheidung zwischen 
Vektor und String-Array auch im Zusammenhang mit sizeof bzw. der 
Typumwandlung zwischen beiden, beibehält, bleibt man konsistent.

Es gibt andererseits gewisse syntaktische Übereinstimmungen in der 
Benutzung von Vektoren und Zeigern, die einen irreführen können.

Na, das hast Du jetzt ja hinter Dir. ;-)
Gast #1809080
Lesenswert?

..ich war mal so frei und hab Dein Programmstück etwas umgebaut - etwas 
kürzer und wesentlich leichter lesbar. Und weniger unnötiges rumkopiere 
:-) Funktioniert aber nur, wenn Du wirklich ∗Strings∗ verschicken willst 
(falls nicht musst Du einen expliziten Längenparameter mitziehen und die 
Schleifenbedingung in der while-Schleife adäquat anpassen). Ich hoffe 
ich habe die Semantik erhalten..

Der Einfachheit halber hab ich die transmit-Funktionen zu einer 
zusammengefasst.
1
$ cat main.c 
2
#include <stdio.h>
3
#include <string.h>
4

5
void transmit(char x)
6
{
7
        printf("%c", x);
8
}
9

10
void SIMKNX_wert_setzen(char objectnumber, char* value)
11
{
12
        char kommando[] = "ovs( )";
13
        kommando[4] = objectnumber;
14
        transmit('0' +strlen(kommando));
15
        transmit('\n');
16

17
        for (int i = 0; i < strlen(kommando); i++)
18
        {
19
                transmit(kommando[i]);
20
        }
21

22
        char* p = value;
23
        while (*p)
24
                transmit(*p++);
25
}
26

27

28
int main()
29
{
30
        SIMKNX_wert_setzen('1', "Hallo Welt!\n");
31
}
32
$ gcc -Wall -std=c99 -o main main.c
33
$ ./main 
34
6
35
ovs(1) Hallo Welt!
#1809083
Lesenswert?

Ich übergeb es jetzt als Parameter ;-)

Darf ich nochmal kurz ne Frage nachschieben ? Lohnt sich nicht dafür nen 
extra Thread aufzumachen.
1
void SIMKNX_wert_senden(unsigned int value, unsigned int objectnumber, unsigned int length) // Wert, SIMKNX Objektnummer, Länge in byte
2
{
3

4
// Wert auf Objekt setzen: ovs(ObjNr) Wert
5

6
  if (length == 2)
7
  {
8
    unsigned char lengthvalue[4];
9
    lengthvalue[0] = length+1;
10
    lengthvalue[1] = ((value/2));  //Vorkommastelle
11
    lengthvalue[2] = 0x2C;      //,
12
    lengthvalue[3] = (value%2);  //Nachkommastelle

nehmen wir an es wurde für value 155(dez) übergeben.

dann steht in lengthvalue[1] nach der Zuweisung 77, da geh ich mit, ist 
richtig.
Aber in lengthvalue[3] steht 1 obwohl eigentlich 5 drinnen stehen 
sollte.
Wo liegt der Fehler? an der Deklararion oder ?
Gast #1809089
Lesenswert?

> lengthvalue[3] = (value%2);  //Nachkommastelle
[..]
> Aber in lengthvalue[3] steht 1 obwohl eigentlich 5 drinnen stehen
> sollte.

Modulo n (n>1) kann nur Werte 0..(n-1) ergeben. Für n=2 liegt 5 
definitiv nicht in jenem Bereich :-)
#1809336
Lesenswert?

Muss nochmal den tread missbrauchen da ich wieder so einen Hänger 
drinnen hab. Und weis wiede rnicht warum das nicht so geht wie ich mir 
das vorstelle:
1
if(Kesseltemp != nutzdaten[7] )//|| nutzdaten[7] > (Kesseltemp+1)
2
      {
3
        USART_KESSEL_Transmit(Kesseltemp); //zu Debugzwecken
4
        SIMKNX_wert_senden(nutzdaten[7],2,2);
5

6
        Kesseltemp = nutzdaten[7];
7
        USART_KESSEL_Transmit(Kesseltemp);//zu Debugzwecken
8
        USART_KESSEL_Transmit(nutzdaten[7]);//zu Debugzwecken
9
      }
Diese If Anweisung wird immer wieder durchlaufen obwohl nach dem 1. 
Durchlauf Kesseltemp gleich 155(dez) und nutzdaten[7] auch 155 ist.
Das lass ich mir mit USART_KESSEL über seriell ausgeben. Warum 
durchläuft der die if Anweisung obwohl die Bedingung eigentlich nicht 
erfüllt sein sollte?

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