Уважаемые мастера! просветите пожалуйста все ли правильно я делаю, и если нет укажите наошибки:
Есть Функция
void * TimerAdd(набор параметров)
{
struct TimerStruct * tempTimerEl = (struct TimerStruct *) malloc (sizeof(struct TimerStruct));
...
тело функции
...
return tempTimerEl;
}
далее определяется массив (подразумевается массив указателей на void)
void ** TimerKLZ;
выделяется память под массив указателей на void
if (CountKLZ > 0)
if ((TimerKLZ= (void **) malloc(sizeof(void *)*CountKLZ))==NULL)
{
free(Data);
return 0;
}
и далее собственно вызов и присвоение
for (i=0; i<CountKLZ; i++)
{
TimerKLZ[i]=TimerAdd(параметры);
}
Re: Правильно ли используется выделение памяти и пользование
Т.е. во-первых, никакого приведения типа не надо, и, во-вторых, 'sizeof' лучше натравить на указатель-получатель, а не на тип.
Не понятно почему тип возврата — 'void*', а не 'struct TimerStruct*'.
V>далее определяется массив (подразумевается массив указателей на void) V> void ** TimerKLZ;
V>выделяется память под массив указателей на void
АТ>Т.е. во-первых, никакого приведения типа не надо, и, во-вторых, 'sizeof' лучше натравить на указатель-получатель, а не на тип.
Понятно, спасибо, это я учту, но вот что сказано в helpe на malloc
char *str;
/* allocate memory for string */if ((str = (char *) malloc(10)) == NULL)
{
printf("Not enough memory to allocate buffer\n");
exit(1); /* terminate program if out of memory */
}
то есть приведение типа явно указано, как я понимаю ошибки в моем описании нет,
и вы представили лишь улучшение или я не до конца что то понимаю?
АТ>Не понятно почему тип возврата — 'void*', а не 'struct TimerStruct*'. Да собственно и не знаю почему просто tempTimerEl это элемент списка, для которого
выделяется память и заполняются поля, далее возращается в качестве результата функции
чтобы потом по идентификатору tempTimerEl его можно было найти в списке и удалить
вот такой функцией unsigned char DeleteTimer(void * ID_Timer) опять же с типом void *
то есть по сути TimerKLZ[i] используется в следующем виде DeleteTimer(TimerKLZ[i]);
на самом деле в качестве void* подразумевался просто возвращаемый адрес элемента
в принципе все работает и вроде стабильно, но посто закрались смутные сомнения
правильно ли я выделяю память для списка указателей на void в таком виде:
АТ>По-прежнему не понятно, почему массив именно 'void*'-ов...
вопрос а как мне объявить массив указателей на TimerStruct?
таким же образом? "struct TimerStruct ** TimerKLZ;" — ???
и потом выделение
Здравствуйте, Roman Odaisky, Вы писали:
АТ>>никакого приведения типа не надо
RO>...но лучше его всё же писать. Для forward compatibility
Как раз таки наоборот. Лучше его не писать, ибо явное приведение типа в такой ситуации может привести к маскированию грубой ошибки. А именно, если автор кода забудет включить заголовочный файл с корректным объявлением 'malloc', то компилятор С выполнит неявное объявление 'malloc' с подразумеваемым типом возврата 'int'. Без приведения типа попытка присваивания этого 'int' указателю сразу приведет к ошибке компиляции, а с приведением типа код будет принят и ошибка окажется замаскированной. На платформе с одинаковым размером указателя и 'int' это еще может худо-бедно "работать", но в общем случае — беда.
Поэтому существует достаточно известный совет — никогда не приводите тип возврата 'malloc'.
Best regards,
Андрей Тарасевич
Re[3]: Правильно ли используется выделение памяти и пользова
АТ>>Т.е. во-первых, никакого приведения типа не надо, и, во-вторых, 'sizeof' лучше натравить на указатель-получатель, а не на тип.
V>Понятно, спасибо, это я учту, но вот что сказано в helpe на malloc V>
V> char *str;
V> /* allocate memory for string */
V> if ((str = (char *) malloc(10)) == NULL)
V> {
V> printf("Not enough memory to allocate buffer\n");
V> exit(1); /* terminate program if out of memory */
V> }
V>
В стародавние времена в языке С не было указателей на 'void' и функция 'malloc' возвращала 'char*'. По этой причине в те времена было принято всегда применять приведение типа к результату 'malloc' (даже если нужен был именно 'char*'). Вот этот пример их help-а как раз и демонстирурует эту давно устаревшую манеру. Старинный пример забыли подправить. Или было просто лень.
Сейчас наоборот выполнять такое приведение типа весьма и весьма не рекомендуется. По причинам, описанным в моем соседнем сообщении.
V>то есть приведение типа явно указано, как я понимаю ошибки в моем описании нет, V>и вы представили лишь улучшение или я не до конца что то понимаю?
Ошибки нет, есть избыточность. И потенциальная опасность.
АТ>>Не понятно почему тип возврата — 'void*', а не 'struct TimerStruct*'. V> Да собственно и не знаю почему просто tempTimerEl это элемент списка, для которого V>выделяется память и заполняются поля, далее возращается в качестве результата функции V>чтобы потом по идентификатору tempTimerEl его можно было найти в списке и удалить V>вот такой функцией unsigned char DeleteTimer(void * ID_Timer) опять же с типом void *
По прежнему не понятно, почему не сделана типизация...
V>то есть по сути TimerKLZ[i] используется в следующем виде DeleteTimer(TimerKLZ[i]); V>на самом деле в качестве void* подразумевался просто возвращаемый адрес элемента V>в принципе все работает и вроде стабильно, но посто закрались смутные сомнения V>правильно ли я выделяю память для списка указателей на void в таком виде:
V>
Формально правильно, но опять же — в такой записи содержатся ненужные инварианты и избыточные приведения. Если завтра ты решишь перейти с типа 'void*' на какой-нибудь другой, тебе придется сделать исправления в трех местах: объявление 'TimerKLZ', приведение типа и "параметр" 'sizeof'. В моем варианте исправление пришлось бы делать только в первом месте а строчку с 'malloc' вообще исправлять бы не надо было.
АТ>>По-прежнему не понятно, почему массив именно 'void*'-ов... V>вопрос а как мне объявить массив указателей на TimerStruct? V>таким же образом? "struct TimerStruct ** TimerKLZ;" — ???
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>>никакого приведения типа не надо
RO>>...но лучше его всё же писать. Для forward compatibility
АТ>Как раз таки наоборот. Лучше его не писать, ибо явное приведение типа в такой ситуации может привести к маскированию грубой ошибки. А именно, если автор кода забудет включить заголовочный файл с корректным объявлением 'malloc', то компилятор С выполнит неявное объявление 'malloc' с подразумеваемым типом возврата 'int'. Без приведения типа попытка присваивания этого 'int' указателю сразу приведет к ошибке компиляции, а с приведением типа код будет принят и ошибка окажется замаскированной. На платформе с одинаковым размером указателя и 'int' это еще может худо-бедно "работать", но в общем случае — беда.
АТ>Поэтому существует достаточно известный совет — никогда не приводите тип возврата 'malloc'.
Большое спасибо за то что просветили, но
вопрос такой, а я вроде и не включаю никакой заголовочный файл с коректным описанием,
я думал что по умолчанию malloc возвращает указатель на воид так и в хелпе объявлено, или это не так?
при этом без приведения типа также компилируется
Re[5]: Правильно ли используется выделение памяти и пользова
Здравствуйте, vis1979, Вы писали:
V>вопрос такой, а я вроде и не включаю никакой заголовочный файл с коректным описанием, V>я думал что по умолчанию malloc возвращает указатель на воид так и в хелпе объявлено, или это не так? V>при этом без приведения типа также компилируется
Хм... Компилятор-то не знает, что там в хелпе объявлено. Более того, компилятор сам по себе ни о каком 'malloc' и слыхом не слыхивал. Чтобы он узнал о существовании 'malloc' надо в транслируемые фалы включать стандартный заголовочный файл 'stdlib.h'.
Вполне возможно, что в твоем случае этот файл как-то неявно включился, через посредство других заголовочных файлов. Поэтому без приведения типа и компилируется. Тем не менее рекомендуется включить его явно.
Best regards,
Андрей Тарасевич
Re[6]: Правильно ли используется выделение памяти и пользова
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Хм... Компилятор-то не знает, что там в хелпе объявлено. Более того, компилятор сам по себе ни о каком 'malloc' и слыхом не слыхивал. Чтобы он узнал о существовании 'malloc' надо в транслируемые фалы включать стандартный заголовочный файл 'stdlib.h'.
АТ>Вполне возможно, что в твоем случае этот файл как-то неявно включился, через посредство других заголовочных файлов. Поэтому без приведения типа и компилируется. Тем не менее рекомендуется включить его явно.
Действительно, в каждый модуль проекта добавлен некий файл.h в котором порписан #include <stdlib.h>
достаточно ли такого описания либо нужно указать его явно в модуле, не будет ли в таком случае
перекресного вызова заголовочных файлов?