Strona 1 z 1

Kopiowanie danych pomiędzy tablicami

: sobota 26 gru 2015, 16:49
autor: Antystatyczny
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!

Re: Kopiowanie danych pomiędzy tablicami

: sobota 26 gru 2015, 18:03
autor: Antystatyczny
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...

Re: Kopiowanie danych pomiędzy tablicami

: sobota 26 gru 2015, 19:37
autor: Antystatyczny
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

Re: Kopiowanie danych pomiędzy tablicami

: sobota 26 gru 2015, 23:02
autor: mokrowski
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 ...

Re: Kopiowanie danych pomiędzy tablicami

: sobota 26 gru 2015, 23:03
autor: Antystatyczny
I cała para w gwizdek... Robię coś, co już jest zrobione :) Zaraz to obejrzę, dzięki

Re: Kopiowanie danych pomiędzy tablicami

: niedziela 27 gru 2015, 14:36
autor: Antystatyczny
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