logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[AVR] Pobieranie danych z bufora do struktury

gafek 03 Sty 2011 20:47 2536 16
  • #1 8953385
    gafek
    Poziom 17  
    Witam,

    dzisiaj stanąłem na wydawałoby się prostej sprawie.

    Jest sobie bufor, do którego pobieram pewne dane bajt po bajcie.
    Następnie te dane chcę przekazać do wcześniej zadeklarowanej struktury.
    Elementy struktury są typu long, czyli dla AVR 4 bajty.
    Uproszczony kod wygląda mniej więcej tak:
    
    
    #include <mega32.h>
    #include <stdio.h>
    
    void main(void)
    {
    
    struct _test
    {
    unsigned long dana;
    };
    
    struct _test test;
    
    char bufor[10];
    
    //wypełniamy bufor
    bufor[0]=0x11;
    bufor[1]=0x22;
    bufor[2]=0x33;
    bufor[3]=0x44;
    
    //kopiujemy do struktury
    test.dana=(unsigned long)bufor[0];
    
    printf("test:%08X\n\r",test.dana);
    
    }
    


    I nic z tego nie wychodzi. Zamiast spodziewanego wyniku 44332211 Hex, otrzymuję 00000011 Hex.

    Wydawało mi się, że takie rzutowanie zadziała i do struktury pobrane zostaną kolejne cztery bajty z bufora. Jest jednak inaczej. Gdzie popełniam błąd ??

    Andrzej.
  • Pomocny post
    #2 8953494
    tmf
    VIP Zasłużony dla elektroda
    Rzutowanie działa, tyle, że bufor jest typu char, więc rzutuje ci char na long i masz to co masz :) Niestety z rzutowaniem nic więcej nie osiągniesz. Twój problem za to rozwiąże coś takiego:
    memcpy(&test, bufor, sizeof(long));
  • #3 8953525
    zumek
    Poziom 39  
    tmf napisał:
    ...problem za to rozwiąże coś takiego:
    memcpy(&test, bufor, sizeof(long));

    Albo...coś takiego :D
    
    char bufor[10];
    unsigned long *ptrtoul=(unsigned long*)bufor;
    
    //.....
    
    //kopiujemy do struktury
    test.dana=*ptrtoul;
  • #5 8953746
    mirekk36
    Poziom 42  
    A można byłoby też to zrobić tak:

    
    union _test 
    { 
        char bufor[4]; 
        unsigned long dana; 
    }; 
    


    i wtedy po napełnieniu bufora:

    
    test.bufor[0]=0x11; 
    test.bufor[1]=0x22; 
    test.bufor[2]=0x33; 
    test.bufor[3]=0x44; 


    od razu bez żadnego rzutowania możesz sobie sprawdzić:

    printf("test:%08X\n\r",test.dana);
  • #6 8953812
    tomekgl
    Poziom 16  
    Można też rozwiązać ten problem definiując unię struktury i char[]. Wtedy dane będą w jednym miejscu w pamięci.
    EDIT:
    Nie widziałem postu kolegi mirekk36. Właśnie tak mogłoby to wyglądać
  • #7 8954124
    gafek
    Poziom 17  
    Dzięki za tyle odpowiedzi !!
    Człowiek potyka się o kamienie, a nie o góry. :)
    A może ktoś wyjaśni mi różnicę pomiędzy:
    test.dana = *(unsigned long *)bufor;

    a
    test.dana=*(unsigned long *)&bufor[0];


    Wydawało mi się, że w każdym przypadku wskazujemy na początek bufora, a wyniki mam różne...

    Takie rzutowanie stosowałem już wcześniej, ale zauważyłem jedną rzecz.
    Pakuję jedną porcję danych do bufora i rzutuję na bufor pierwszą strukturę.
    Potem następna porcja danych, ale rzutuję już inną strukturę. Efekt - dane w pierwszej strukturze nadpisują się tymi nowymi danymi dla drugiej struktury w buforze.

    Czy nie jest tak, że w takim przypadku rzutowania dane fizycznie przechowywane są wciąz w obszarze bufora, a kompilator pamięta tylko ich adresy i nie tworzy nowej kopii tych danych (w strukturze) ?
  • Pomocny post
    #8 8954367
    sulfur
    Poziom 24  
    tmf: Nie zupełnie. Problemem tutaj jest to, że autor tematu rzutuje wartość, a nie wskaźnik na adres w pamięci. Poprawne rzutowanie w tym wypadku podał kolega szelus.

    gafek: Te dwa kody robią to samo. Nie mogą działać różnie. Jeśli tak jest, to problem jest gdzieś indziej. Co do reszty, kompilator nic sam nie robi. Jak każesz mu skopiować obiekt to go skopiuje. Jak przypiszesz lub skopiujesz wskaźnik na obszar pamięci to tak się stanie. Proszę się nauczyć, że nic nie dzieje się automagiczne.
  • #9 8954431
    gafek
    Poziom 17  
    Tak, ale czy w przypadku, który podał kolega Szelus nie jest właśnie tak, że operujemy na wskażnikach do danych w buforze, a nie na kopiach tych danych w strukturze ? To by wyjaśniało, dlaczego zawartość pierwszej struktury jest nadpisywana przez kolejne zapełnienie bufora danymi dla drugiej struktury. Wskażniki w obydwu strukturach wskazują na dokładnie te same adresy w przestrzeni bufora.

    Poprawcie mnie jesli sie mylę...
  • #10 8954476
    sulfur
    Poziom 24  
    Nie. Patrząc od prawej do lewej: rzutowanie adresu bufor na unsigned long, następnie "pobranie" wartości i skopiowanie jej do zmiennej dana. Jeśli w jakimś kodzie występuje wspomniana przez kolegę właściwość to proszę go wkleić, bo na pewno nie jest to kod z pierwszego postu tego wątku.
  • #11 8954546
    Fredy
    Poziom 27  
    A mógłby któryś z kolegów dokładnie wytłumaczyć czemu nie działa kod Autora z początku tego wątku?
  • #12 8954592
    mirekk36
    Poziom 42  
    Fredy napisał:
    A mógłby któryś z kolegów dokładnie wytłumaczyć czemu nie działa kod Autora z początku tego wątku?


    to już opisał tmf przecież, bo:

    test.dana=(unsigned long)bufor[0];


    to rzutowanie wartości char w postaci jednego bajtu z tablicy bufor[0] na unsigned long. Nie może to więc inaczej zadziałać niż tak jak objawiało się to autorowi w pierwszym poście.

    wartość 0x11 została zamieniona na unsigned long 0x00000011
    inaczej się sprawa ma w przypadku tego co podał szelus

    *(unsigned long*)bufor;


    to z kolei jak tłumaczył sulfur powoduje, pobranie wartości spod adresu(wskaźnika) *bufor tyle że po drodze znajduje się jeszcze (unsigned long*) co powoduje, że następuje rzutowanie typu wskaźnika - innymi słowy mówiąc mówi to kompilatorowi aby potraktował to co kryje się pod tym adresem jako wskaźnik do typu unsigned long dzięki czemu pobrane zostaną 4 bajty.
  • #13 8954602
    sulfur
    Poziom 24  
    A co tu tłumaczyć. Kod w pierwszym wątku pobiera ośmiobitową wartość 0x11 i tą wartość rzutuje na więcej-bitową (32 bitową) wartość unsigned long. Ale to jest cały czas ta sama wartość 0x11.

    Ad. No w zasadzie ładnie to opisał mirekk36. Podsumowując, różnica polega w kolejności wykonywania czynności. W oryginalnym kodzie jest pobranie wartości i rzutowanie, a w poprawce dokonanej przez szelus rzutowanie i pobranie wartości.
  • #14 8954735
    gafek
    Poziom 17  
    sulfur napisał:
    Jeśli w jakimś kodzie występuje wspomniana przez kolegę właściwość to proszę go wkleić, bo na pewno nie jest to kod z pierwszego postu tego wątku.


    No to proszę bardzo. Jest to mały wycinek mojego programu przygotowany tak, aby się skompilował, który działa dokładnie tak jak opisałem. Rzutowanie kolejnej struktury na bufor niszczy poprzednią strukturę. Wg mnie to logiczne, bo operujemy na wskażnikach do danych w buforze, a nie na kopiach danych w strukturze.

    Ale zapodaję kod do analizy:
    
    #define F_CPU	20945000
    #define BAUD 57600
    
    
    #include <mega32.h>
    #include <stdio.h>
    
    struct _icodir_header {
    	unsigned int reserved; //zawsze 0
      	unsigned int type;
      	unsigned int imgnumber;
    	};
    
    struct _ico_header{
      	char width;
      	char height;
      	char colors;
      	char reserved; //zawsze 0
      	unsigned int colorplanes;
      	unsigned int bitspp;
      	unsigned long int sizeinbytes;
      	unsigned long int offset;
    	};
    
    void main(void)
    {
    
    struct _icodir_header* icodir_header;
    struct _ico_header* ico_header;
    
    char bufor[100];
    
    /* Inicjalizacja USART'u*/
    UCSRB = 0x00; 
    UCSRA=0x00; 
    UCSRC=0x86; 
    /* ustawiamy prędkość */
    UBRRH=(F_CPU/16/BAUD-1) >> 8;
    UBRRL=(F_CPU/16/BAUD-1) & 0xFF;
    UCSRB=0x18;
    
    
    /*tutaj program czyta z pliku, ale do testów wypełniamy bufor "na piechotę"*/
    
    bufor[0]=0x01;
    bufor[1]=0x02;
    bufor[2]=0x03;
    bufor[3]=0x04;
    bufor[4]=0x05;
    bufor[5]=0x06;
    bufor[6]=0x07;
    bufor[7]=0x08;
    bufor[8]=0x09;
    bufor[9]=0x0a;
    bufor[10]=0x0b;
    bufor[11]=0x0c;
    bufor[12]=0x0d;
    bufor[13]=0x0e;
    bufor[15]=0x0f;
    
        icodir_header=(struct _icodir_header*)bufor;//rzutowanie nagłówka ICODIRECTORY
    
        //sprawdzamy co skopiowaliśmy do struktury icodir_header
        printf("\n\rICON DIRECTORY:\n\r");
        printf("Reserved:%04X\n\r",icodir_header->reserved);
        printf("type:%04X\n\r",icodir_header->type);
        printf("icons in file:%04X\n\r",icodir_header->imgnumber);
    
    
    /*tutaj program wczytuje kolejną porcję danych z pliku do bufora.
    My znów zrobimy to na piechotę*/
    
    bufor[0]=0x11;
    bufor[1]=0x12;
    bufor[2]=0x13;
    bufor[3]=0x14;
    bufor[4]=0x15;
    bufor[5]=0x16;
    bufor[6]=0x17;
    bufor[7]=0x18;
    bufor[8]=0x19;
    bufor[9]=0x1a;
    bufor[10]=0x1b;
    bufor[11]=0x1c;
    bufor[12]=0x1d;
    bufor[13]=0x1e;
    bufor[15]=0x1f;
    
    /*rzutujemy na bufor drugą strukturę*/        
            ico_header=(struct _ico_header*)bufor;
        	
    /*a teraz z powrotem sprawdzamy pierwszą strukturę ICO_DIR*/
    
    	printf("\n\rICON DIRECTORY po raz drugi:\n\r");
        printf("Reserved:%04X\n\r",icodir_header->reserved);
        printf("type:%04X\n\r",icodir_header->type);
        printf("icons in file:%04X\n\r",icodir_header->imgnumber);
    
    
    /* i kupa ! mamy już zupełnie inne dane w pierwszej strukturze.
    Dokładnie dane wczytane drugi raz do bufora*/
    
    
    }
    


    efekt na ekranie:

    ICON DIRECTORY:
    Reserved:0201
    type:0403
    icons in file:0605


    ICON DIRECTORY po raz drugi:
    Reserved:1211
    type:1413
    icons in file:1615

    Czyli jednak....
  • #15 8955042
    tmf
    VIP Zasłużony dla elektroda
    Oczywiście, że w tym przypadku nadpisujesz dane, bo przecież one się nie kopiują, tylko zmieniasz sposób interpretacji tablicy - ale tej samej tablicy. Koledze sulfur chodziło o sugerowaną różnicę pomiędzy:
    test.dana = *(unsigned long *)bufor;
    a
    test.dana=*(unsigned long *)&bufor[0];
    Powyższe kody są sobie równoważne.
  • #16 8955116
    sulfur
    Poziom 24  
    Oczywiście. Niech kolega zamieni
    struct _icodir_header icodir_header;

    icodir_header=*(struct _icodir_header*)bufor;//rzutowanie nagłówka ICODIRECTORY 
    
        //sprawdzamy co skopiowaliśmy do struktury icodir_header 
        printf("\n\rICON DIRECTORY:\n\r"); 
        printf("Reserved:%04X\n\r",icodir_header.reserved); 
        printf("type:%04X\n\r",icodir_header.type); 
        printf("icons in file:%04X\n\r",icodir_header.imgnumber);
    Może się okazać, że linijka
    icodir_header=*(struct _icodir_header*)bufor;//rzutowanie nagłówka ICODIRECTORY 
    nie przejdzie, wtedy trzeba zastosować kopiowanie za pomocą funkcji memcpy podanej przez kolegę tmf na początku tematu. Analogicznie postępujemy z drugim odczytem.
  • #17 8955258
    gafek
    Poziom 17  
    Cytat:

    Oczywiście. Niech kolega zamieni
    Kod:
    struct _icodir_header icodir_header;


    Dokładnie tak zrobiłem dzisiaj rano. Jak się człowiek wyśpi to od razu inaczej myśli. :D

    Dane do struktury kopiuję przez
     memcpy(&icodir_header, bufor, sizeof(icodir_header));

    Jedyny minus to zwiększenie potrzeb jeśli chodzi o pamięć, bo teraz rzeczywiście tworzona jest kopia wycinka bufora. W poprzednim wypadku fizycznie dane znajdowały się wciąż w buforze.

    Dzięki wszystkim za pomoc !!
    Andrzej.
REKLAMA