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

[ATmega32][C] - Uszkodzona komórka pamięci, czy to możliwe?

BartekWB 20 Sty 2016 11:04 1773 19
  • #1 15352201
    BartekWB
    Poziom 27  
    Cześć

    Posiadam w kodzie następującą strukturę:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    którą wypełniam testowymi danymi w następującej funkcji:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    a następnie zapisuję na kartę pamięci za pomocą biblioteki FatFS.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Te wszystkie chary z ptr_to_text[n] mam zapisane w pamięci FLASH korzystając z PROGMEM.

    Wszystko wydaje się być pięknie, ale na karcie pamięci dostaje taki oto wynik:
    Kod: HTML, XML
    Zaloguj się, aby zobaczyć kod


    Wszystkie inne zmienne ze struktury gnss_data działają poprawnie! Tylko hours marudzi i nie mogę jej w żaden sposób poprawnie odczytać. Macie jakiś pomysł dlaczego tak się dzieje?
  • #3 15352244
    BlueDraco
    Specjalista - Mikrokontrolery
    Odczytujesz zapewne poprawnie, tzn. pierwszy bajt ma wartość 0, bo taką wpisałeś. Nie tylko tam zresztą.
  • #4 15352273
    BartekWB
    Poziom 27  
    Nie do końca rozumiem. Czyli powinienem wszystkie pola char w strukturze powiększyć o 1 i dodawać do każdego \0 ? To samo tyczy się stringów zapisanych w pamięci FLASH?

    Edit:

    Zrobiłem tak jak opisałem powyżej:

    Wszystkie pola+1 na znak końca stringa
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I podczas wypełniania:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Dostaje na karcie:
    Kod: HTML, XML
    Zaloguj się, aby zobaczyć kod


    Czyli nie do końca to czego się spodziewałem, ale pojawiło się jedno "h" z godziny co jest jakimś krokiem do przodu.
    Jakieś wskazówki?
  • Pomocny post
    #5 15352389
    BlueDraco
    Specjalista - Mikrokontrolery
    Wystarczy napisać np.
    strncp(data->hdop, "12.3456", 7);

    i nie musisz powiększać pól.

    Zapis "11.111111\0" jest bez sensu, bo definiuje w pamięci obiekt zajmujący 11 bajtów, zakończony dwoma zerami, z których pierwsze jest kopiowane przez strcpy().

    Wszystkie Twoje problemy wynikają z niezrozumienia, czym jest łańcuch w języku C. Dopóki tego nie przyswoisz, nie bierz się za programowanie.
  • #6 15352454
    BartekWB
    Poziom 27  
    Masz rację, jestem programistą wysokopoziomowym, co mocno upośledza, teraz jest dla mnie niepojęte, że muszę dbać o takie rzeczy.
    Nie rozumiem tego, skoro inne zmienne działają poprawnie, to dlatego ta jedna się sypie?

    Postąpiłem zgodnie z Twoją radą:
    Rozmiary pól bez zmian wielkości:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Dalej postępuje tak samo:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Co daje w efekcie w dalszym ciągu niepoprawny odczyt godziny:
    Kod: HTML, XML
    Zaloguj się, aby zobaczyć kod


    Zgodnie z tym tutorialem http://www.tutorialspoint.com/cprogramming/c_strings.htm powinienem jednak zadbać o dodatkowe pole na zakończenie stringa.

    Dodałem po jednym polu w rozmiarze:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    i nareszcie dostaje poprawny wynik!

    Kod: HTML, XML
    Zaloguj się, aby zobaczyć kod


    Dzięki za nakierowanie mnie!
  • #7 15352614
    tmf
    VIP Zasłużony dla elektroda
    BartekWB napisał:
    Masz rację, jestem programistą wysokopoziomowym, co mocno upośledza, teraz jest dla mnie niepojęte, że muszę dbać o takie rzeczy.


    Co rozumiesz przez "programista wysokopoziomowy"? Bo to o czym koledzy piszą to podstawy C. O tym jak kończony jest łańcuch i że kończący znak NUL też zajmuje miejsce w pamięci trzeba po prostu wiedzieć niezależnie, czy pisze się program na MCU czy PC. Pisząc na PC w większości języków, dostałbyś w tym przypadku identyczne, błędne rezultaty.
  • #8 15352647
    BartekWB
    Poziom 27  
    Głównie piszę w JavaScript i C#, gdzie po prostu problemów tego typu nie ma, o wiele bardziej łopatologicznie się pisze. Asemblerowcy pewnie napiszą zaraz, że C to wysoki poziom, zależy od punktu widzenia ;).
  • Pomocny post
    #9 15352661
    Konto nie istnieje
    Konto nie istnieje  
  • #10 15352751
    BartekWB
    Poziom 27  
    Dziękuje za ostrzeżenie. Zmodyfikowałem mój kod tak, aby kopiować długość stringa + 1.
  • #11 15352817
    BlueDraco
    Specjalista - Mikrokontrolery
    Racja, zamiast strncpz powinno być memcpy. strncpy wrzuci 0 na koniec, a tego właśnie mieliśmy uniknąć.
  • #12 15352829
    tmf
    VIP Zasłużony dla elektroda
    Piotrus_999 napisał:
    Jedna rzecz jeszcze nt strncpy - to dość "niebezpieczna" funkcja. Jezeli dlugośc stringu który kopiujesz bedzie wiekszy lub równy ilosci znakow do kopiowania to nie będzie zera na koncu !!!


    A czemu miałoby być, jeśli określasz wprost ile znaków ma być skopiowane? Jak się kopiuje całe łańcuchy to używa się strcpy i żadne magiczne wyliczenia nie są potrzebne. A jeśłi trzeba ograniczyć długość łańcucha to należy użyć strlcpy, które obcina łańcuch z dodaniem NUL na koniec.
    Także zamiast kombinować, wystarczy poznać język, którego się używa.

    Dodano po 3 [minuty]:

    Piotrus_999 napisał:


    tmf napisał:
    Co rozumiesz przez "programista wysokopoziomowy"?


    Pewnie chodzi o jezyki gdzie istnieje string jako samodzielny byt a nie po prostu tablica char. Lisp, PHP, javascript, java, c# etc etc., oraz gdzie elementy stringu niekoniecznie musza byc bajtami (np znakami Unicode), a wszystko załatwia za nas kompilator / interpreter.


    Mylisz się. W C też można zapomnieć o takich niuansach, lecz nie jeśli programista postanowił odwoływać się do elementów łańcucha zamiast łańcucha. Jeśli traktujesz łańcuch jako tablicę to we wszystkich językach sprawa wygląda tak samo.
  • #13 15352939
    Konto nie istnieje
    Konto nie istnieje  
  • #14 15353268
    tmf
    VIP Zasłużony dla elektroda
    Piotrus_999 napisał:
    tmf napisał:
    A czemu miałoby być, jeśli określasz wprost ile znaków ma być skopiowane? Jak się kopiuje całe łańcuchy to używa się strcpy i żadne magiczne wyliczenia nie są potrzebne.


    Bo to jest cos z str na poczatku a nie mem. A nie zachowuje sie jak funkcja stringowa. A str powinien dac string jako wynik a nie cos nieokreslonego.


    A co to za pomysł w ogóle, że strncpy to funkcja operująca na łańcuchach? Trzeba czytać co się używa. strncpy ma skopiować nie więcej niż n-znaków i to robi. Jaki sens byłoby tworzyć funkcję, która jawnie jako argument przyjmuje liczbę znaków, po czym niejawnie, zupełnie magicznie ignoruje argument i kopiuje sobie inną liczbę znaków? A, że większość osób uważających, że umie programować, tak naprawdę nie umie, to mamy to co mamy.

    Dodano po 3 [minuty]:

    Piotrus_999 napisał:

    tmf napisał:
    W C też można zapomnieć o takich niuansach, lecz nie jeśli programista postanowił odwoływać się do elementów łańcucha zamiast łańcucha. Jeśli traktujesz łańcuch jako tablicę to we wszystkich językach sprawa wygląda tak samo.


    Tu sie niestety Ty myslisz. Unicode strings ? Automatic string allocation? i wiele wiele innych.
    Jeszcze niektóre funkcje jak strncpy (nota bene z tego co wiem to jest bład historyczny, bo to nie tak miało wygladac :))


    Zacznij rozróżniać operacje na łańcuchach od operacji na znakach tworzących łańcuch. Jak wygląda np. w C# operacja identyczna do operacji wykonanej przez autora tematu, czyli alokacji 9 bajtowego obszaru i skopiowanie w niego 9 znaków z łańcucha?
  • #15 15353453
    grko
    Poziom 33  
    Dziwny jest fakt jak wiele osób posługuje się funkcją strncpy kompletnie źle. Przykłady:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Efekt działania każdego z tych wywołań jest równy zastosowaniu memcpy, tylko że wolniej.
    Intencją autora tej funkcji (pomijając jej sensowność ;)) było takie użycie aby nie zapisywać obszaru poza rozmiarem parametru dst. Czyli użycie tych funkcji ma sens w ten sposób:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Albo jak chcemy mieć pewność, że na końcu znajdzie się null terminator:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Jednak w powyższym przypadku użyć lepiej strlcpy, która dopiero od niedawna jest dostępna w libc.
  • #16 15353665
    Konto nie istnieje
    Konto nie istnieje  
  • #17 15353681
    grko
    Poziom 33  
    @BlueDraco
    Cytat:

    Nie jest. Ty też posługujesz się nią źle, więc nie wiem, dziwi Cięto, że ktoś inny posługuje się nią źle.
    ;)


    Mógłbyś rozwinac swoja myśl? Nie sa te wywołania równoważne z memcpy? Czy może jest szybciej.
    Gdzie się posługuję źle?

    Cytat:

    jedna uwaga. sizeof(x) zadziala oczywiście przy deklaracji char x[] = "inicjalizacja"' lub char x[cos tam]. W przypadku deklaracji
    char *x = "ala ma kota" - zwróci nam wielkosć wskaznika.


    Dobra uwaga. Ale czegoś takiego:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    nie będziesz używał jako dst? Niemniej jednak trzaba uważać.

    Zachownie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    jest identyczne jak memcpy. Nie ma sensu tego używać w ten sposób
  • #18 15353696
    BlueDraco
    Specjalista - Mikrokontrolery
    Ok, racja, inną funkcją posługujesz się źle. Te akurat przykłady złe nie były.
  • #19 15353727
    grko
    Poziom 33  
    Cytat:

    Ok, racja, inną funkcją posługujesz się źle. Te akurat przykłady złe nie były.


    No coś zawsze gdzieś musi być źle ;) Pozdrawiam.
  • #20 15353751
    Konto nie istnieje
    Konto nie istnieje  
REKLAMA