+130
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
#include <stdlib.h>
struct no_matter
{
int some_field;
};
struct matter *do_stuff(void)
{
struct no_matter *m = calloc(1, sizeof *m);
return m;
}
int main(void)
{
struct no_matter *m = do_stuff();
free(m);
return 0;
}
Сегодня выполняю роль гумна. В сишке можно возвращать указатель на непонятно откуда взявшуюся необъявленную ранее структуру и код будет компиляться (ладно хоть пишет невнятные ворнинги, только благодаря им нашёл опечатку в одной букве в имени структуры в рабочем коде). Понятно, что все указатели одинаково числа, но всё равно как-то некрасиво. Хацкелисты негодуэ, даёшь монаду Ptr
http://ideone.com/3SABHW
Запостил: roman-kashitsyn,
27 Ноября 2012
Steve_Brown 27.11.2012 10:58 # 0
defecate-plusplus 27.11.2012 11:34 # 0
структура объявлена до первого использования, calloc честно выделяет память, free честно удаляет её
roman-kashitsyn 27.11.2012 11:40 # +2
> struct no_matter *
calloc и free здесь не при чём, они просто отражают ситуацию, с которой я столкнулся.
Я знаю, почему это работает, мне просто не нравится, что оно должно компилиться (теперь только -Werror, только хардкор).
defecate-plusplus 27.11.2012 11:45 # +1
с первого раза и не углядишь даже
roman-kashitsyn 27.11.2012 11:49 # +1
Вот и я о том же: ещё один отличный способ выстрелить себе в ногу.
defecate-plusplus 27.11.2012 11:59 # 0
как и использование необъявленных типов
FireBurd 27.11.2012 11:43 # +1
bormand 27.11.2012 12:15 # +1
я всегда буду обновлять тред перед отправкой комментария
я всегда буду обновлять тред перед отправкой комментария
я всегда буду обновлять тред перед отправкой комментария
я всегда буду обновлять тред перед отправкой комментария
DBdev 27.11.2012 14:48 # +2
> я всегда буду обновлять тред перед отправкой комментария
> я всегда буду обновлять тред перед отправкой комментария
> я всегда буду обновлять тред перед отправкой комментария
Каждый раз, когда не обновляешь - на 1 строчку больше дописываешь?
bormand 27.11.2012 14:58 # 0
Fai 27.11.2012 15:00 # +4
bormand 27.11.2012 15:02 # +4
Steve_Brown 27.11.2012 15:07 # +5
Fixed.
TarasB 27.11.2012 11:41 # +1
roman-kashitsyn 27.11.2012 11:47 # +1
Просто можно указателю на одну структуру присвоить указатель на другую, и сишка это съест.
Видимо, Ритчи изобрёл Dynamic Typing задолго до того, как это стало мэйнстримом.
TarasB 27.11.2012 11:50 # +2
roman-kashitsyn 27.11.2012 11:56 # 0
Это возможно далеко не всегда. Например, если размер структуры не известен клиентскому коду (а в моём случае это верно чуть чаще чем всегда: клиенты работают с загадочным struct something *, не зная, что внутри).
Экземпляры порождаются/уничтожаются с помощью allocate_something() / deallocate_something(), за правильный вызов отвечает клиент.
defecate-plusplus 27.11.2012 12:05 # +3
1) вызываем с параметром "длина моего буфера - 0", получаем "длина твоего буфера будет 25 см"
2) вызываем с "длина моего буфера - 25 см", получаем "окей, теперь смотри сам свой буфер"
TarasB 27.11.2012 12:09 # +2
roman-kashitsyn 27.11.2012 12:58 # −1
Что-то мне подсказывает, что это чревато race-conditions (необходимая длина буфера может поменяться между вызовами). Да и аллокации в куче это избежать не особо помогает, разве что через alloca, чревытый последствиями.
defecate-plusplus 27.11.2012 13:08 # +4
если передать 0, вызов говорит error_more_data и говорит сколько (25 см)
вызываем с 25 см, вызов говорит error_more_data и говорит, что теперь надо 30 см
выделяем 40 см, вызов говорит "ок, записал 30 см"
но в целом это не очень хорошо, если длина может так меняться от двух последовательных вызовов
да и вообще - сишкопроблемы
roman-kashitsyn 27.11.2012 13:10 # 0
TarasB 27.11.2012 13:12 # 0
Гораздо хуёвее, если функция "заполни мне буфер" не принимает размер буфера. Она просто заполняет его как есть. И такая дыра есть в некотрых контролах ВинАПИ. Но это похуй, потому что похакать интерфейс и так есть много куда более простых способов, чем попасть в тот момент, когда программ уже узнала размер буфера, но ещё не отправила запрос на копирование данных.
roman-kashitsyn 27.11.2012 13:21 # +3
Или записывают в свой локальный буфер и возвращает указатель на него.
Это вообще эпик фейлы стандартной сишной библиотеки (gets, sprintf, localtime, etc. - это ещё один пример того, когда не надо повторять за разработчиками api).
bormand 27.11.2012 15:08 # +1
Да и хакеров, в плохом смысле этого слова, тогда еще не было, а юзеры не вводили всякий хлам, поэтому gets и sprintf не вызывали ни у кого опасений...
Хорошее было время...
P.S. Еще доставляет имя функции creat(). Такое ощущение, что имена были ограничены пятью символами.
roman-kashitsyn 27.11.2012 15:18 # +3
Некоторые линковщики не воспринимали больше шести.
Ken Thompson was once asked what he would do differently if he were redesigning the UNIX system. His reply: "I'd spell creat with an e."
Yuuri 27.11.2012 17:21 # +2
TarasB 27.11.2012 12:10 # 0
roman-kashitsyn 27.11.2012 12:49 # 0
Для небольшого числа относительно крупных объектов (например, том псевдо-файловой системы) использую кучу. Кстати, в моём случае в качестве struct no_matter была struct test_suite, гуляющая между функциями.
TarasB 27.11.2012 12:11 # +1
bormand 27.11.2012 12:20 # 0
"Простите, но в треде появились новые сообщения, или кто-то что-то исправил."
TarasB 27.11.2012 13:10 # +1
Проблема в том, что сток показывает только первую версию комментария, которая до редактирования.
bormand 27.11.2012 13:32 # 0
bormand 27.11.2012 15:11 # 0
Steve_Brown 27.11.2012 15:26 # 0
eth0 27.11.2012 19:16 # +2
3.14159265 27.11.2012 20:26 # +1
И потихоньку Говнокод превращается... превращается Говнокод... в говногитхаб.
guest 27.11.2012 22:24 # +3
Предыдущая версия комментария содержала ссылки на неавторитетные источники, поэтому была отклонена.
Fai 28.11.2012 00:19 # +2
Звучит как Виктория Копро.