Kopiowanie danych pomiędzy tablicami

Tu możesz pisać o swoich problemach z pisaniem programów w języku C dla AVR.
Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1177
Rejestracja: czwartek 03 wrz 2015, 22:02

Kopiowanie danych pomiędzy tablicami

Postautor: Antystatyczny » sobota 26 gru 2015, 16:49

Witam,

Siedzę na funkcją char *asctime(const struct tm *brokentime);

Usiłuję wpisać do tablicy wynik działania funkcji itoa, czyli de facto chce skopiować zawartość tablicy temp do tablicy result. Pokażę całą fukcję, byście mieli pełny obraz sytuacji... Obecnie kompilator wypluwa błąd o następującej treści:

../asctime.c:65:23: error: lvalue required as increment operand
*resultptr++ = *temp++;

Ok, a teraz listing:

Kod: Zaznacz cały

#include<stdint.h>
#include<stdlib.h>
#include<limits.h>
#include"time.h"

static const char wday_name[7][4] =
{
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char mon_name[12][4] =
{
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static char result[26];


char* asctime(const struct tm *brokentime)
{

   char *resultptr = result;
   char temp[5];//for itoa conversions

   if(!brokentime) return 0;//address is unavailable?
   
   //variable out of range check
   if(brokentime->tm_sec  < 0 || brokentime->tm_sec  > 60) return 0;
   if(brokentime->tm_min  < 0 || brokentime->tm_min  > 59) return 0;
   if(brokentime->tm_hour < 0 || brokentime->tm_hour > 23) return 0;
   if(brokentime->tm_mday < 0 || brokentime->tm_mday > 31) return 0;
   if(brokentime->tm_mon  < 0 || brokentime->tm_mon  > 11) return 0;
   if(brokentime->tm_year < 0 || brokentime->tm_year > (INT_MAX-1900) ) return 0;
   if(brokentime->tm_wday < 0 || brokentime->tm_wday > 6) return 0;
   if(brokentime->tm_yday < 0 || brokentime->tm_yday > 365) return 0;

   //weekday
   for(uint8_t i = 0; i < 3; i++)
   {
      *resultptr++ = wday_name[brokentime->tm_wday][i];
   }

   *resultptr++ = ' ';

   //month

   for(uint8_t i = 0; i < 3; i++)
   {
      *resultptr++ = mon_name[brokentime->tm_mon][i];
   }

   *resultptr++ = ' ';

   //day of month

   if(brokentime->tm_hour < 10) *resultptr++ = '0';
   itoa(brokentime->tm_hour, temp, 10);

   while(*temp)
   {
      *resultptr++ = *temp++;//copy data from temp to result (without null)   <---- tu jest błąd
   }

   *resultptr++ = ':';

   return result;
}


Działanie tej funkcji polega na tym, by wszystkie pola struktury przekazanej przez wskaźnik do tej funkcji przemaglować na postać ASCII, wrzucić do statycznej tablicy result, a wskaźnik na nią zwrócić jako wynik funkcji. Ostateczna postać wyniku ma wyglądać mniej więcej tak:

Sun Dec 26 16:48:33 2015\n

Może ktoś się pochyli nad moją funkcją i powie, jak bardzo źle się do tego zabieram... :)

Pozdrawiam!
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1177
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: Kopiowanie danych pomiędzy tablicami

Postautor: Antystatyczny » sobota 26 gru 2015, 18:03

Błędem było to, że temp było nazwą tablicy, a nie wskaźnikiem na nią. Wiem, nazwa tablicy to wskaźnik na jej zerowy element...i tu właśnie tkwił błąd. Nie można manipulować wskaźnikiem, który zawsze ma wskazywać na zerowy element tablicy. Powołałem więc wskaźnik na tablicę i to nim manipuluję. Poniżej przedstawiam działającą funkcję asctime()

Kod: Zaznacz cały

#include<stdint.h>
#include<stdlib.h>
#include<limits.h>
#include"time.h"

static const char wday_name[7][4] =
{
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char mon_name[12][4] =
{
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static char result[26];
static char temp[5];

char* asctime(const struct tm *brokentime)
{

   char *resultptr = result;
   char *tempptr = temp;//for itoa conversions

   if(!brokentime) return 0;//address is unavailable?

   //variable out of range check
   if(brokentime->tm_sec  < 0 || brokentime->tm_sec  > 60) return 0;
   if(brokentime->tm_min  < 0 || brokentime->tm_min  > 59) return 0;
   if(brokentime->tm_hour < 0 || brokentime->tm_hour > 23) return 0;
   if(brokentime->tm_mday < 0 || brokentime->tm_mday > 31) return 0;
   if(brokentime->tm_mon  < 0 || brokentime->tm_mon  > 11) return 0;
   if(brokentime->tm_year < 0 || brokentime->tm_year > (INT_MAX-1900) ) return 0;
   if(brokentime->tm_wday < 0 || brokentime->tm_wday > 6) return 0;
   if(brokentime->tm_yday < 0 || brokentime->tm_yday > 365) return 0;

   //weekday
   for(uint8_t i = 0; i < 3; i++)
   {
      *resultptr++ = wday_name[brokentime->tm_wday][i];
   }

   *resultptr++ = ' ';

   //month
   for(uint8_t i = 0; i < 3; i++)
   {
      *resultptr++ = mon_name[brokentime->tm_mon][i];
   }

   *resultptr++ = ' ';

   //day of month
   if(brokentime->tm_mday < 10) *resultptr++ = '0';
   itoa(brokentime->tm_mday, temp, 10);

   while(*tempptr)
   {
      *resultptr++ = *tempptr++;//copy data from temp to result (without null)
   }

   *resultptr++ = ' ';

   //hour
   tempptr = temp;

   if(brokentime->tm_hour < 10) *resultptr++ = '0';
   itoa(brokentime->tm_hour, temp, 10);

   while(*tempptr)
   {
      *resultptr++ = *tempptr++;//copy data from temp to result (without null)
   }

   *resultptr++ = ':';

   //minutes
   tempptr = temp;
   if(brokentime->tm_min < 10) *resultptr++ = '0';
   itoa(brokentime->tm_min, temp, 10);

   while(*tempptr)
   {
      *resultptr++ = *tempptr++;//copy data from temp to result (without null)
   }

   *resultptr++ = ':';

   //seconds
   tempptr = temp;
   if(brokentime->tm_sec < 10) *resultptr++ = '0';
   itoa(brokentime->tm_sec, temp, 10);

   while(*tempptr)
   {
      *resultptr++ = *tempptr++;//copy data from temp to result (without null)
   }

   *resultptr++ = ' ';

   //year
   tempptr = temp;
   itoa((brokentime->tm_year + 1900), temp, 10);

   while(*tempptr)
   {
      *resultptr++ = *tempptr++;//copy data from temp to result (without null)
   }

   *resultptr++ = '\n';
   *resultptr = 0;

   return result;
}


Przechwytywanie.PNG


Na razie przerzucanie danych zrobione jest niemal na piechotę, bo chciałem w ogóle od czegoś zacząć. Widać wyraźnie, że część kodu wielokrotnie się powtarza, a to się kłóci z DRY (don't repeat yourself). Myślę, że stworzenie helpera z tych powtarzających się kawałków kodu radykalnie poprawi sytuację. Mile widziane wszelkie sugestie...
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1177
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: Kopiowanie danych pomiędzy tablicami

Postautor: Antystatyczny » sobota 26 gru 2015, 19:37

Dokonałem kilku zmian w funkcji i wydaje mi się, że teraz jest bardziej przejrzyście. Dodałem dwa helpery, by wykonywały krecią robotę. W dalszym ciągu proszę o uwagi... A teraz najnowsza wersja (również działająca):

Kod: Zaznacz cały

#include<stdint.h>
#include<stdlib.h>
#include<limits.h>
#include"time.h"

static const char wday_name[7][4] =
{
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char mon_name[12][4] =
{
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static char result[26];

static char *concat_int_helper(int val, char *buf)
{
   char temp[5];
   uint8_t idx = 0;

   if(val < 10) *buf++ = '0';
   itoa(val, temp, 10);

   while(temp[idx])
   {
      *buf++ = temp[idx];
      idx++;
   }

   return buf;
}

static char *concat_helper(const char *src, char *dst)
{
   while(*src)
   {
      *dst++ = *src++;
   }
   return dst;
}

char* asctime(const struct tm *brokentime)
{
   char *resultptr = result;
   
   if(!brokentime) return 0;//address is unavailable?

   //variable out of range check
   if(brokentime->tm_sec  < 0 || brokentime->tm_sec  > 60) return 0;
   if(brokentime->tm_min  < 0 || brokentime->tm_min  > 59) return 0;
   if(brokentime->tm_hour < 0 || brokentime->tm_hour > 23) return 0;
   if(brokentime->tm_mday < 0 || brokentime->tm_mday > 31) return 0;
   if(brokentime->tm_mon  < 0 || brokentime->tm_mon  > 11) return 0;
   if(brokentime->tm_year < 0 || brokentime->tm_year > (INT_MAX-1900) ) return 0;
   if(brokentime->tm_wday < 0 || brokentime->tm_wday > 6) return 0;
   if(brokentime->tm_yday < 0 || brokentime->tm_yday > 365) return 0;

   //weekday
   resultptr = concat_helper(&wday_name[brokentime->tm_wday][0], resultptr);
   *resultptr++ = ' ';
   //month
   resultptr = concat_helper(&mon_name[brokentime->tm_mon][0], result);
   *resultptr++ = ' ';
   //day of month
   resultptr = concat_int_helper(brokentime->tm_mday, resultptr);
   *resultptr++ = ' ';
   //hour
   resultptr = concat_int_helper(brokentime->tm_hour, resultptr);
   *resultptr++ = ':';
   //minute
   resultptr = concat_int_helper(brokentime->tm_min, resultptr);
   *resultptr++ = ':';
   //second
   resultptr = concat_int_helper(brokentime->tm_sec, resultptr);
   *resultptr++ = ' ';
   //year
   resultptr = concat_int_helper((brokentime->tm_year + 1900), resultptr);
   *resultptr++ = '\n';
   *resultptr = 0;

   return result;
}

Dodaję również spakowany programem 7z kompletny projekt dla Eclipse.
Zegarek_V2.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
mokrowski
User
User
Posty: 190
Rejestracja: czwartek 08 paź 2015, 20:50
Lokalizacja: Tam gdzie Centymetro

Re: Kopiowanie danych pomiędzy tablicami

Postautor: mokrowski » sobota 26 gru 2015, 23:02

Odpowiedź na szybko to: zerknij do źródeł avr-libc. Tam jest już zrobiony nagłówek time.h i reszta (włącznie z "obsługą słońca") :-)
Żebyś nie szukał (albo nie instalował specjalnie svn'a) załączam.

A i forum nie przyjmuje (nie wiem czemu) plików o rozszerzeniu xz. Stąd plik powinien nazywać się: avr-libc.tar.xz. Rozpakujesz go 7zip'em. xz bije na głowę inne kompresory :-) (w zip'ie plik miał 6 MB... )
 ! Wiadomość z: acid3
już obsługuje ...
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
,,Myślenie nie jest łatwe, ale można się do niego przyzwyczaić" - Alan Alexander Milne: Kubuś Puchatek

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1177
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: Kopiowanie danych pomiędzy tablicami

Postautor: Antystatyczny » sobota 26 gru 2015, 23:03

I cała para w gwizdek... Robię coś, co już jest zrobione :) Zaraz to obejrzę, dzięki
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1177
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: Kopiowanie danych pomiędzy tablicami

Postautor: Antystatyczny » niedziela 27 gru 2015, 14:36

Rozpakowałem archiwum i przejrzałem. Faktycznie, jest tam cała paczka do obsługi czasu. Niestety nie bardzo wiem, jak to dodać do istniejącego toolchaina Atmel na moim dysku. Nigdzie (w folderze instalacyjnym) nie potrafię znaleźć źródeł, do których mógłbym dodać źródła "biblioteki" time. Mam wrażenie, że wszystkie elementy toolchaina Atmel zostały skompilowane(scalone?) do postaci bibliotek. Jest jakiś sposób, by ożenić ze sobą toolchain Atmel ze źródłami time? A może muszę w całości przejść na toolchain, który rozpakowałem?

Próbowałem dodać do projektu folder time oraz nagłówek time.h. Niby całość się kompiluje, ale dostaję ostrzeżenia o niezrozumieniu symbolu _xmem
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.


Wróć do „Programowanie AVR w C”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 2 gości