anonymous@RULINUX.NET~# Last login: 2018-10-22 18:05:04
Регистрация Вход Новости | Разметка | Пользователи | Галерея | Форум | Статьи | Неподтвержденное | Трекер | Правила форума | F.A.Q. | Ссылки | Поиск
[#] [Добавить метку] [Редактировать]
Скрыть

Вещь посерьёзнее паттернов.

Вот пишу тут мелкую программу с использованием OpenCL. Решил написать на C (пока просто чтобы проверить, как ядро работает). Конечно OpenCL какая-то слишком низкоуровневая байда, чтобы на ней писать без оберток, ИМО.

Там есть тип cl_mem, нужный для обозначения объекта в памяти устройства, который представляет из себя по сути указатель. Далее есть функция, устанавливающая аргумент ядра перед запуском. Вот её прототип:

c

cl_int clSetKernelArg (cl_kernel kernel, cl_uint arg_index,
                       size_t arg_size, const void *arg_value);
 


Видите, void*, да? Далее я пишу:
c

cl_mem mem = ...;
clSetKernelArg (mykernel, 0, sizeof(cl_mem), mem);
 


Программа компилируется без варнингов и исполняется, только на выходе я вижу, что сначала идут ожидаемые данные, а затем NaN. Я полез отлаживать ядро, думал, где-то накосячил с синхронизацией (характерно, что баг то появлялся, то исчезал).

После долгого дебага я решил сравнить свой код с каким-нибудь туториалом. И тут я нашел, что надо писать так:

c

cl_mem mem = ...;
clSetKernelArg (mykernel, 0, sizeof(cl_mem), &mem);
 


Внезапно, всё заработало. Моя вина, да. Но скажите, это нормально, что компилятор пропускает такой косяк без единого возражения, хотя ошибка видна невооруженным глазом? ОК, создатели OpenCL могли бы сделать в заголовках что-то такое:

c


#ifdef _PUBLIC_
struct cl_mem;
cl_mem* clCreateBuffer (/* args dropped */);
#else
struct cl_mem {
...
};
#endif
 
и принимать в clSetKernelArg() указатель на struct cl_mem

Оставим это всё на совести разработчиков. Но дело не в библиотеке, дело в языке! Именно из-за того, что clSetKernelArg принимает последним элементом вообще любой указатель, и приключилась эта дребедень. Вся вина лежит на типе void*. И это ещё хуже, чем Common Lisp с динамической типизацией, который бы, вероятно, скомпилировал бы код с неверными типами, но поймал бы ошибку в рантайме и предупредил бы пользователя, а не выполнился бы с ошибками.

В C++ есть конечно шаблоны и виртуальные методы для того, чтобы не писать код с void*, но зачем там тип void* оставили вообще? Зачем там всякие dynamic_cast и reinterpret_cast? Или вообще обычные касты в C-стиле? Всё это приводит к трудноуловимым ошибкам. А вы говорите, паттерны.

Пилите свои кулстори, как вы писали типобезопасный код на C++ или напарывались на тривиальные ошибки из-за говёной системы типов

Vasily(*) (2018-03-10 12:39:38)

Mozilla/5.0 (X11; FreeBSD) AppleWebKit/602.1 (KHTML, like Gecko) QupZilla/1.8.9 Version/9.0 Safari/602.1

[Ответить на это сообщение]
[#] [Добавить метку] [Редактировать] Ответ на: Вещь посерьёзнее паттернов. от Vasily 2018-03-10 12:39:38
avatar
Скрыть

Re:Вещь посерьёзнее паттернов.

Так к Амурычу претензия в том и состоит, что в его реализации не подразумевается проверка типов. Пока в рантайме всё не наебнётся при каком-нибудь редком стечении обстоятельств - даже и не узнаешь, что проблема существует. А когда наебнётся - фиг найдёшь эту проблему.

anonymous(*)(2018-03-11 13:50:32)

Mozilla/5.0 (X11; Fedora; Linux i686; rv:58.0) Gecko/20100101 Firefox/58.0
[#] [Добавить метку] [Редактировать] Ответ на: Вещь посерьёзнее паттернов. от Vasily 2018-03-10 12:39:38
avatar
Скрыть

Re:Вещь посерьёзнее паттернов.

Может тебе ещё и в scanf-е наворотить ifdef-ов? Там ведь тоже &arg используется вместо arg. Надо понимать что́ ты пишешь.

anonymous(*)(2018-03-12 15:57:44)

[#] [Добавить метку] [Редактировать] Ответ на: Re:Вещь посерьёзнее паттернов. от anonymous 2018-03-12 15:57:44
avatar
Скрыть

Re:Вещь посерьёзнее паттернов.

> Там ведь тоже &arg используется вместо arg
Продолжи свою мысль. Какие ifdef'ы?

c

vasily@vonbraun:~ % cat test.c
#include <stdio.h>

int read_int (const char *line)
{
    int res;
    sscanf (line, "%i", res);

    return res;
}
vasily@vonbraun:~ % cc -c -o test.o test.c
test.c:6:25: warning: format specifies type 'int *' but the argument has type 'int' [-Wformat]
    sscanf (line, "%i", res);
                   ~~   ^~~
1 warning generated.
 


В случае scanf компилятор видит ошибку только за счет формата. Прототип у scanf и у всей stdio пиздобратии вообще убогий:

int sscanf (const char * restrict str, const char * restrict format, ...); По ... вообще не ясно, что в неё можно пихать

Но в C++-то такое говно вполне решено с помощью <<. Хотя опять же если ты не мудак, который пользуется C-style печатью из C++. Как мне видится, большинство проблем с типами в C++ решено, но тем не менее оставлены какие-то дурацкие механизмы, с помощью которых можно написать по-идиотски.

> Надо понимать что́ ты пишешь.
Абсолютно говно аргумент. От очепяток и забывания говноапи никто не застрахован.

Vasily(*)(2018-03-12 23:35:43)
Отредактировано Vasily по причине "не указана"
Mozilla/5.0 (X11; FreeBSD) AppleWebKit/602.1 (KHTML, like Gecko) QupZilla/1.8.9 Version/9.0 Safari/602.1
Этот тред читают 1 пользователь:
Анонимных: 1
Зарегистрированных: 0




(c) 2010-2020 LOR-NG Developers Group
Powered by TimeMachine

Valid HTML 4.01 Transitional Правильный CSS!