www.mikrocontroller.net

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


Autor: Chris Tian (chris0086)
Datum:

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

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

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

  if (length == 2)
  {
    unsigned char lengthvalue[4];
    lengthvalue[0] = length+1;
    lengthvalue[1] = ((value/2));  //Vorkommastelle
    lengthvalue[2] = 0x2C;      //,
    lengthvalue[3] = (value%2);  //Nachkommastelle
    
    USART_KESSEL_Transmit(sizeof (lengthvalue));  //Hier steht noch eine 4
    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.

Autor: Floh (Gast)
Datum:

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

Autor: Chris Tian (chris0086)
Datum:

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

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
:-)

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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:
void SIMKNX_wert_setzen(uint8_t objectnumber, unsigned char *value)
{
  int i;
  int j = 0;
  unsigned char kommando[(sizeof (value) ) + 6]; //sollte bei dem Beispiel 10 ergeben dann passt alles
  USART_KESSEL_Transmit(sizeof (kommando));
  kommando[0] = 0x6F; //O
  kommando[1] = 0x76; //v
  kommando[2] = 0x73; //s
  kommando[3] = 0x28; //(

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

      kommando[i] = value[j];
      j++;
      }
  for( i = 0; i < sizeof( kommando ) / sizeof( *kommando ); i++ )
    {
      SIMKNX_Transmit(kommando[i]);
    }
}

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: narf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dann schreib doch auch
  kommando[0] = 'O'; 
  kommando[1] = 'v'; 
  kommando[2] = 's'; 
  kommando[3] = '('; 
  kommando[4] = objectnumber;
  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

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Dummy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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. ;-)

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
$ cat main.c 
#include <stdio.h>
#include <string.h>

void transmit(char x)
{
        printf("%c", x);
}

void SIMKNX_wert_setzen(char objectnumber, char* value)
{
        char kommando[] = "ovs( )";
        kommando[4] = objectnumber;
        transmit('0' +strlen(kommando));
        transmit('\n');

        for (int i = 0; i < strlen(kommando); i++)
        {
                transmit(kommando[i]);
        }

        char* p = value;
        while (*p)
                transmit(*p++);
}


int main()
{
        SIMKNX_wert_setzen('1', "Hallo Welt!\n");
}
$ gcc -Wall -std=c99 -o main main.c
$ ./main 
6
ovs(1) Hallo Welt!

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich übergeb es jetzt als Parameter ;-)

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

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

  if (length == 2)
  {
    unsigned char lengthvalue[4];
    lengthvalue[0] = length+1;
    lengthvalue[1] = ((value/2));  //Vorkommastelle
    lengthvalue[2] = 0x2C;      //,
    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 ?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 155 / 2 = 77,5 deswegen soll da 5 stehen

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

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke an alle für die Hilfe es wird Zeit fürs Bett...

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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:
if(Kesseltemp != nutzdaten[7] )//|| nutzdaten[7] > (Kesseltemp+1)
      {
        USART_KESSEL_Transmit(Kesseltemp); //zu Debugzwecken
        SIMKNX_wert_senden(nutzdaten[7],2,2);

        Kesseltemp = nutzdaten[7];
        USART_KESSEL_Transmit(Kesseltemp);//zu Debugzwecken
        USART_KESSEL_Transmit(nutzdaten[7]);//zu Debugzwecken
      }
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?

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat sich erledigt, mann sollte doch gleiche Datentypen 
vergleichen...Idiot

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.