Forum: Mikrocontroller und Digitale Elektronik Problem mit Funktion: Pointer falsche Arraygröße


von Chris T. (chris0086)


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.

von Floh (Gast)


Lesenswert?

value ist nur ein Pointer (Adresszeiger) und auf einem AVR 2 Byte groß.

von Chris T. (chris0086)


Lesenswert?

Und wie müsst ichs schrieben damit ich da die 4 hinbekomme? war das 
nicht das mit dem & ?

von Floh (Gast)


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.
:-)

von Chris T. (chris0086)


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
}

von Floh (Gast)


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 :-)

von Chris T. (chris0086)


Lesenswert?

erklärst du mir wie das Nullbyte dazu beiträgt die Länge zu berechnen? 
bei der 2. Möglichkeit?
Aber werd wohl die erste nehmen.

von narf (Gast)


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

von Klaus W. (mfgkw)


Lesenswert?

Christian Hohmann schrieb:
> erklärst du mir wie das Nullbyte dazu beiträgt die Länge zu berechnen?

steht in jedem C-Buch im Kapitel über Strings.

von Klaus W. (mfgkw)


Lesenswert?

narf schrieb:
> sizeof wird zu gern verwendet .. ist aber ein präprozessoraufruf ..

nein, es ist ein Operator (was hier aber nichts zur Sache tut)

von Dummy (Gast)


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. ;-)

von g457 (Gast)


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!

von Chris T. (chris0086)


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 ?

von Klaus W. (mfgkw)


Lesenswert?

Christian Hohmann schrieb:
> Aber in lengthvalue[3] steht 1 obwohl eigentlich 5 drinnen stehen
> sollte.

Wieso 5?
Irgendwas modulo 2 kann nur 0 oder 1 sein (Rest der
ganzzahligen Division durch 2)

von g457 (Gast)


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 :-)

von Chris T. (chris0086)


Lesenswert?

dann hab ich was falsch verstanden, ok was ich da drin stehen haben will 
ist 5.
155 / 2 = 77,5 deswegen soll da 5 stehen aber hab wohl wieder was 
vermehrt.

von g457 (Gast)


Lesenswert?

> 155 / 2 = 77,5 deswegen soll da 5 stehen

lengthvalue[3] = (value %2) *5;

von Chris T. (chris0086)


Lesenswert?

Danke an alle für die Hilfe es wird Zeit fürs Bett...

von Chris T. (chris0086)


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?

von Chris T. (chris0086)


Lesenswert?

Hat sich erledigt, mann sollte doch gleiche Datentypen 
vergleichen...Idiot

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.