реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> функция получения даты, на линуксе
romez777
сообщение Dec 13 2005, 09:40
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Приветствую.
Написал простую функцию (работаю под линуксом) возвращающую текущую дату, все бы ноормально но одна немаловажная проблема - утечка памяти. Потому как не могу в функци вызвать free(d), тогда нечего возвращать. Я уже совсем туплю, не знаю как обойти это smile.gif Нужна рекомендация

char* get_date(void)
{
time_t curtime;
struct tm *loctime;
char *d;

if ( !(d = malloc(9)) )
return NULL;

curtime = time(NULL); /* get сurrent time */
loctime = localtime(&curtime); /* convert to localtime representation */
strftime(d, 9, "%m/%d/%y", loctime);

return d;
}

Заранее благодарю!
Go to the top of the page
 
+Quote Post
Виктория
сообщение Dec 13 2005, 10:31
Сообщение #2


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Код
void get_date(char *d)
{
  time_t curtime;
  struct tm *loctime;
  
  curtime = time(NULL); /* get сurrent time */
  loctime = localtime(&curtime); /* convert to localtime representation */
  strftime(d, 9, "%m/%d/%y", loctime);

}


wink.gif
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Dec 13 2005, 15:39
Сообщение #3


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Или вызвать free после вызова Вашей функции и использования результата.
Но это оччччень плохое решение!!!
Go to the top of the page
 
+Quote Post
zaratustra
сообщение Dec 15 2005, 13:51
Сообщение #4


Участник
*

Группа: Новичок
Сообщений: 65
Регистрация: 18-11-05
Пользователь №: 11 054



char * cdate(char *now_date)
{
static struct timeval tv;
struct tm tm0;
struct timezone tz;

gettimeofday(&tv, &tz);
localtime_r(&tv.tv_sec, &tm0);
sprintf(now_date,"%04d/%02d/%02d", tm0.tm_year+1900, tm0.tm_mon+1, tm0.tm_mday);
return now_date;
}
Go to the top of the page
 
+Quote Post
Виктория
сообщение Dec 15 2005, 14:28
Сообщение #5


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Конечно же smile.gif, zaratustra - это самый правильный подход, собственно так и делается во всех библиотечных функциях и понятно почему.

Сообщение отредактировал Vic1 - Dec 15 2005, 14:33
Go to the top of the page
 
+Quote Post
Леший
сообщение Dec 15 2005, 16:13
Сообщение #6


Участник
*

Группа: Свой
Сообщений: 34
Регистрация: 7-07-04
Из: Москва
Пользователь №: 283



Я пользуюсь такой функцией:

....

#define TIME_FORMAT "%02i:%02i:%02i %02i/%02i/%04i"

......



char *gettimestr (void)
{
static char timestr[80];
static time_t rawtime;
static struct tm *Now;

time (&rawtime);
Now = localtime (&rawtime);
snprintf (timestr, 72, TIME_FORMAT,
Now->tm_hour, Now->tm_min, Now->tm_sec, Now->tm_mday, Now->tm_mon + 1,
Now->tm_year + 1900);
return timestr;

}

2 zaratustra & Vic1:
Можно, конечно и так, но:
1. При каждом вызове надо следить за размером буфера (да и не забыть его создать сначала)
2. Рано или поздно после вызова функции про free забудешь, а ловить такие ошибки довольно занудноsad.gif

Сообщение отредактировал Леший - Dec 15 2005, 16:22
Go to the top of the page
 
+Quote Post
Olej
сообщение Dec 16 2005, 06:51
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 351
Регистрация: 11-09-05
Из: Харьков
Пользователь №: 8 458



Цитата(romez777 @ Dec 13 2005, 13:40) *
Написал простую функцию (работаю под линуксом) возвращающую текущую дату, все бы ноормально но одна немаловажная проблема - утечка памяти. Потому как не могу в функци вызвать free(d), тогда нечего возвращать.


Проблема не имеет касательства к конкретной функции - это давняя проблема возврата структурированных значений. Часто решается так:

Код
char* get_date(void) {
  time_t curtime;
  struct tm *loctime;
  char d[ 9 ];
  curtime = time(NULL); /* get сurrent time */
  loctime = localtime(&curtime); /* convert to localtime representation */
  strftime(d, 9, "%m/%d/%y", loctime);
  return strdup( d );     /* вот здесь возвращается структурная копия в стеке */
}


P.S. Очень часто в таких случаях решение с внутренними static переменными, как показывали выше - оптимальное.

P.P.S. Эта же проблема, но куда острее - стоит при передаче копии структурной переменной в качестве параметра в функцию потока, и часто вот такое решение (на 1-й взгляд "горбатое" wink.gif) оказывается наилучшим, что-то типа:

Цитата(IgorKossak @ Dec 13 2005, 19:39) *
Или вызвать free после вызова Вашей функции и использования результата.
Но это оччччень плохое решение!!!


Код
struct Param {
...
};

void* ThreadProc( void *data ) {
   Param *p = (Param)data;
   // используем экземпляр data без копирования...
   ...
   delete p;
   return NULL;
};

// вызывающая единица
...
while( /* нечто */ )
   pthread_create( NULL, NULL, &ThreadProc, new Param( ... ) );


- структура создаётся в одной программной единице, а уничтожается - в другой! Но все другие решения - ещё хуже wink.gif

Сообщение отредактировал Olej - Dec 16 2005, 07:20
Go to the top of the page
 
+Quote Post
Виктория
сообщение Dec 16 2005, 09:40
Сообщение #8


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Ответ мой и zaratustra - это как надо бы, когда операционной системы точно нет (хотя и присутствуют функции динамического выделения памяти). Для функции получения даты и строки из 9 символов нет необходимости с malloc(), можно использовать статический буфер, причем для разных строк, по мере необходимости. Внутренние статические переменные - примерно тоже самое, но их уж множество (в данном случае множество строк, вместо одной).
Пример уважаемого Olej со структурной копией в стеке не очень понятен. Копия живет до перезаписи ее в стеке? Не случится ли это раньше, чем она потребуется?

Конечно, разговор о стиле программирования это немного smile.gif bb-offtopic.gif (и мои замечания тоже), тем более он разный в зависимости от использования/неиспользования операционной системы, иногда и конкретной ОС, условий задачи (например, условие реентерабельности get_date()) и т.п.

Сообщение отредактировал Vic1 - Dec 16 2005, 09:49
Go to the top of the page
 
+Quote Post
Olej
сообщение Dec 16 2005, 19:48
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 351
Регистрация: 11-09-05
Из: Харьков
Пользователь №: 8 458



Цитата
Конечно, разговор о стиле программирования это немного smile.gif bb-offtopic.gif (и мои замечания тоже), тем более он разный в зависимости от использования/неиспользования операционной системы, иногда и конкретной ОС, условий задачи (например, условие реентерабельности get_date()) и т.п.


Этот вопрос - это обсуждение сугубо не стиля программирования, а вопросов написания кода, свободного от скрытых ошибок, которые потом можно выявлять годами... Стиль программирования - это когда споры идут до хрипоты какой из эквивалентных фрагментов кода "правильный", а какой "ущербный":

Код
if( ... ) {
   cout << "terminal error";
   return( EXIT_FAILURE );
};


или

Код
if( ... ) cout << "terminal error", exit( EXIT_FAILURE );


Цитата
Ответ мой и zaratustra - это как надо бы, когда операционной системы точно нет (хотя и присутствуют функции динамического выделения памяти).


Функция malloc() - это API stdlib, в не зависимости от среды выполнения, и должна обеспечиваться любой совместимой С-системой, если таковая хочет нею считаться wink.gif, ... а если нет - то кто же ей доктор wink.gif.

Цитата
Пример уважаемого Olej со структурной копией в стеке не очень понятен. Копия живет до перезаписи ее в стеке? Не случится ли это раньше, чем она потребуется?


- нет, копия, выделенная в стеке будет жить гораздо дольше wink.gif ... перезаписи её в стеке ... потому что перезаписи просто не будет! Если вы помните, стандарт С ISO/IEC 9899 1999 (называемый ANSI C 99) окончательно стандартизовал возврат любого сколь угодно сложной структуриры как результата выполнения функци ... раньше это было: "... это можно - это нельзя, ... здесь селёдку заворачивали(с) ...". Как это может происходить? Смотрим такой фрагмент (я для чистоты эксперимента - использую pure C а не C++):

Код
typedef struct { char d[ 20 ]; } X; // sizeof( X ) = 20
. . .
struct X func1( struct X Y ) {
   return Y;
};
. . .
void func2( void ) {
...
   struct X Y = func( X );
};


- сколько стека будет выделено при вызове func1? ответ: 40 байт - для области возврата + области копии параметров;
- в каком порядке они будут заталкиваться в стек? ответ: именно в таком, как сказано выше: область возврата + копии параметров + локальные переменные (если они есть - у нас нет);
- сколько копирований (байт?) будет при вызове-возврате? ответ: 3 (60 байт) - копирование параметра - копирование в область возврата - копирование присваивания;
- как и кем будет освобождаться стек? это уже интереснее, для это придётся вспомнить соглашения о вызовах некоторых языковых средств, например:

- PASCAL (BASIC, FORTRAN, ADA, OBERON, MODULA2): параметры заталкиваются в стек слева-направо, сама процедура должна восстановить стек перед return;
- C/C++ (PROLOG): параметры заталкиваются в стек справа-налево, вызывающий код должен восстановить стек после return;
- STDCALL (WIN32): параметны заталкиваются как С, а стек освобождается как PASCAL (Господи, это ж надо такое придумать!);
- WATCOM: первые (слева-направо) параметры грузятся в регистры EAX, EDX, EBX, ECX (сколько влезет ), а уж остальные заталкиваются в стек справа-налево как С;

Так вот - код вызывающей единицы С/С++ свернёт область стека после выполнения, но не область возврата структурного результата. Эта область остаётся распределённой как и область локальных переменных вызывающей единицы. Вопрос - когда же она освободится? - тогда же, когда и локальные переменные вызвавшей единицы - при выходе за область видимости вызывающей единицы (именно её завершении).

А чтобы не быть голословным, я вам продемонстрирую ассемблерный код, сгенерированный в подобном случае компилятором GCC 2.95 (ведь исходный вопрос был о Linux?):

Код
#define SIZE 1024   // только для степени 2 и простоты разбора
struct A { char B[ SIZE ]; } C;

struct A POW( struct A E ) { return E; };

int main( void ) {
   struct A D = POW( C );
   return 0;
};



И вот что из него получается:

Код
    
POW:
   pushl %ebp
   movl %esp,%ebp
   pushl %edi
   pushl %esi
   movl 8(%ebp),%eax
   movl %eax,%edi
   leal 12(%ebp),%esi
   cld
   movl $256,%ecx
   rep
   movsl
   movl %eax,%eax
   leal -8(%ebp),%esp
   popl %esi
   popl %edi
   leave
   ret $4

main:
   pushl %ebp
   movl %esp,%ebp
   subl $1040,%esp
   pushl %edi
   pushl %esi
   leal -1024(%ebp),%eax
   addl $-12,%esp
   addl $-1024,%esp
   movl %esp,%edi
   movl $C,%esi
   cld
   movl $256,%ecx
   rep
   movsl
   pushl %eax
   call POW
   addl $1036,%esp
   xorl %eax,%eax
   leal -1048(%ebp),%esp
   popl %esi
   popl %edi
   leave
   ret

   .comm   C,1024,32


Можете убедиться:
- структура из 1024 байт перед вызовом побайтно (у компилятора хватило ума сделать это 4-х байтными словами) копируется в стек, который "прогибается" вниз на 1024;
- возвращаемая структура также копируется в место в стеке, которое "бронируется" вызывающим кодом при завершении вызова.

P.S. Проу прощения за многословность, но такие вещи - проще не объясняются wink.gif.
Go to the top of the page
 
+Quote Post
Виктория
сообщение Dec 19 2005, 08:39
Сообщение #10


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Я немного поясню свой ответ.

Цитата
Этот вопрос - это обсуждение сугубо не стиля программирования, а вопросов написания кода, свободного от скрытых ошибок, которые потом можно выявлять годами... Стиль программирования - это когда споры идут до хрипоты какой из эквивалентных фрагментов кода "правильный", а какой "ущербный":

Глупости все это, если споры идут... wink.gif Я только позволила себе заметить, что не всегда хотелось бы использовать динамическое выделение памяти (через malloc() или стек), особенно в тех случаях, когда без этого можно и обойтись. Ничего против динамического распределения не имею (в порочных связях не состою smile.gif). Очень даже понимаю его полезность и что одна из концепций любой ОС - динамическое выделение.
В старые времена (лет 10-15 назад), когда не применялись ОС в embedded системах (широко) и проблема памяти на борту была актуальна (равно, как и быстродействие ПО), тогда и переменные больше были статические (хотя и программы писались на языке Си). Со временем проблема с памятью и Мегагерцами решилась, ПО целевых систем стало тянутся к большей универсальности и воплощения принципов ОС хотя бы на концептуальном уровне (тенденции развития, как при замене Асма Си). Но знать такой вариант со статической памятью не помешает (как альтернативный). Да и не очень прозрачна линия развития embedded программирования (так как тянет это развитие и немного в сторону и без ОС: Java, MЭК на ПЛК, Labview и вся эта компания..., простите за оффтопик).

Пример с возвратом структурной единицы теперь более понятен, спасибо. В последнем примере - "стек и время все равно жалко" blush.gif (отнесем это к личному "стилю программирования" wink.gif ).
Go to the top of the page
 
+Quote Post
Olej
сообщение Dec 19 2005, 09:51
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 351
Регистрация: 11-09-05
Из: Харьков
Пользователь №: 8 458



Цитата(Vic1 @ Dec 19 2005, 12:39) *
не всегда хотелось бы использовать динамическое выделение памяти (через malloc() или стек), особенно в тех случаях, когда без этого можно и обойтись.


Ну ... динамическое выделение памяти и выделение на стеке ... это, как говорят в Одессе "2 разные вещи": динамическое выделение может потребовать и сотни команд (смотря какой вы используете аллокатор), а на стеке - только 1-ну: добавление к SP фиксированной величины...
Статическое выделение ("когда без этого можно и обойтись") часто уместно, а иногда и лучшее решение ... , но это только когда уместно wink.gif - с ним много своих "нюансов" wink.gif, как например - инициализация :D.

Цитата(Vic1 @ Dec 19 2005, 12:39) *
Пример с возвратом структурной единицы теперь более понятен, спасибо. В последнем примере - "стек и время все равно жалко" blush.gif (отнесем это к личному "стилю программирования" wink.gif ).


В "последнем примере" я заодно показал передачу массива параметру по значению (чего нет в С) - поэтому и так особенно жалко стека, и особенно времени... wink.gif А на самом деле - всё не так уж и плохо.
Go to the top of the page
 
+Quote Post
Виктория
сообщение Dec 19 2005, 10:16
Сообщение #12


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Хоть и под массив, а все равно жалко cheers.gif

Насчет быстродействия кратко: если переменные в стеке - то обычно используется косвенная адресация, если статические в ОЗУ - то прямая, при работе с массивами конечно не очень актуально.

blush.gif - Нету смайлика с поднятыми руками. Я сдаюсь, тема неисчерпаема.
Go to the top of the page
 
+Quote Post
Lagman
сообщение Jan 16 2006, 22:49
Сообщение #13


Знающий
****

Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245



Цитата(romez777 @ Dec 13 2005, 12:40) *
char* get_date(void)
{
time_t curtime;
struct tm *loctime;
char *d;

if ( !(d = malloc(9)) )
return NULL;

curtime = time(NULL); /* get сurrent time */
loctime = localtime(&curtime); /* convert to localtime representation */
strftime(d, 9, "%m/%d/%y", loctime);

return d;
}


А если объявить функцию так:
void get_date (char * rd)
{
..
..
rd = d
free()
}
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 27th July 2025 - 14:21
Рейтинг@Mail.ru


Страница сгенерированна за 0.01468 секунд с 7
ELECTRONIX ©2004-2016