LINUX.ORG.RU

Использование system() VS Использование библиотек

 , ,


1

3

Всем привет!

Интересует ваше мнение. Допустим, хочу написать простую утилиту с GUI на GTK+ на Plain C. Будет отправка файлов на сервер: открываем программу, выбираем в маленьком окошке файл, нажимаем «Отправить» в ответ получаем ссылку на файл на удалённом сервере. Всё просто.

Можно подключить библиотеку cURL, а можно дёргать тотже cURL через system(). Какой подход предпочтительнее и почему?

Помоему, если требуется написать много подобных утилит, как обёртки для простых системных вызовов, то проще использовать system(). Или это считается ужасной практикой и за такое нужно будет гореть в аду?



Последнее исправление: winston3d (всего исправлений: 1)

Гореть в аду.
Замучаешься обрабатывать ошибки и вывод утилит через system(); нужно обязательно проверять есть ли утилита в системе. Проще как библиотеки использовать. + если память не изменяет то на каждый вызов system будет создаваться новый шелл. (+расход памяти,+время инициализации). В общем я б не стал так делать, если не скрипт пишу

CrazyAlex25 ★★★
()
Последнее исправление: CrazyAlex25 (всего исправлений: 1)

За system()? Да.

Потому что эскейпить специальные символы в именах параметров и файлов правильно - это сложно. Велики шансы, что ваша программа в результате не будет поддерживать файлы с пробелами, знаками доллара и кавычками в именах. Погуглите «shell injection».

Хотите запускать процесс - хотя бы передавайте аргументы напрямую, а не через шелл.

anonymous
()
Ответ на: комментарий от anonymous

Да, вопрос безопасности открытый, согласен.

А про использование памяти и CPU, как мне кажется, не критично. Или я ошибаюсь?

В то время, как все пользуются приложениями на Electron и запускают мини-утилиты на Java, экономить системный вызов только в момент отправки файла, как-то странно.

99.999% времени программа будет висеть в трее и ничего не делать...

winston3d
() автор топика
Ответ на: комментарий от winston3d

тогда уж писать на bash иль на ином языке с более юзерфрендли интерфейсом чем фундаментально сложный и требовательный С
чё ресурсы-то экономить. зато как просто - быстренько накидал несколько строчек и в продакшен.

pfg ★★★★★
()
Ответ на: комментарий от pfg

Вообще я сам против Electron и Java на каждый чих, по мне, так это злоупотребление пользовательскими ресурсами.

А экономия одного системного вызова пару раз в день, это на грани разумного. Может быть я ошибаюсь, и поэтому задал этот вопрос.

А Plain C просто интересен как язык, потому и он. Так бы выбрал какой нибудь Python, если хотел бы скорость разработки.

winston3d
() автор топика
Ответ на: комментарий от winston3d

А Plain C просто интересен как язык, потому и он.

Если таки умеете plain C, то компромисным вариантом будет не system/библиотеки, а fork+exec+wait. Это убережет вас от bash+эскейпинга, но даст возможность работать с сложными программами.

vodz ★★★★★
()
Ответ на: комментарий от winston3d

А Plain C просто интересен как язык, потому и он

Раз уж выбрал идеологически Си, то и пиши на Си, как на нем идеологически принято(не через system).

если хотел бы скорость разработки

Ну раз скорость разработки для тебя не так важна, тогда в чем вопрос вообще? Используй либу.

Aswed ★★★★★
()

А с чего вообще у тебя появилась идея пользовать system? Какая в этом выгода? Потому что я могу придумать кучу недостатков этого способа, но при этом не вижу ни одного достоинства.

morse ★★★★★
()
Ответ на: комментарий от Aswed

Ну раз скорость разработки для тебя не так важна, тогда в чем вопрос вообще? Используй либу.

Ты так говоришь, как будто для либы дольше разрабатывать. Если проверять возвращаемый результат у system то как бы не больше строк получилось, чем для libcurl.

redgremlin ★★★★★
()
Ответ на: комментарий от morse

Ну я это вижу примерно так: 1. Программа будет использоваться только на ПК с настроенным окружением (будет установлен cURL). 2. system() в одну строчку написать и отладить сильно проще, чем подтянуть либу и заиспользовать её. 3. Требуется обработка только базовых ошибок.

Просто хочу узнать, нормальное ли это решение в конкретных ситуациях.

winston3d
() автор топика

А, ну вот как раз есть повод спросить у местных экспертов. Значит, есть научный софт (без гуя), юзер задаёт имя директории, куда будут складываться результаты вычислений.

Нужно создать эту директорию, если её ещё нет. Возможны пробелы в имени. Имя может быть вида «foo/bar/baz», и тогда все родительские директории тоже нужно создать.

Сейчас это делает такой код на C++

system(("mkdir -p + '" + path + "'").c_str())

Лаконично и понятно. Но !Ъ, так как system, да и c_str глаза режет (это единственное место, где вообще есть си-строки). Как бы переписать это место?

std::filesystem использовать не получится, так как на целевых машинах зачастую компиляторы без C++17.

Crocodoom ★★★★★
()

system() не надо, разберись с popen() если хочется использовать C по сути как клей и GUI. Например cdebootstrap через popen() вызывает sha256sum для подсчёта хеша вместо использования библиотек и ничего, всё нормально. В идеале конечно использовать нативное API.

system только в том случае если ты просто для себя по бырому статичную команду вызываешь. Или тебе реально нужно сессию shell запустить.

Deleted
()
Ответ на: комментарий от winston3d

Вообще задача прикрутить GUI в достаточно короткие сроки к маленьким операциям, которые легко выполнятся через консоль.

winston3d
() автор топика
Ответ на: комментарий от winston3d

«Одного системного вызова»? system потянет за собой сотню-тысячу. Конечно, для пары раз в день всё равно пофиг.

anonymous
()
Ответ на: комментарий от winston3d

1. не является выгодой конкретного метода.
2. то есть написать system в одну строчку — это легко, а дернуть метод либы в одну строчку — это до фига как сложно?
3. обрабатывать или нет ошибки — это в любом случае твой выбор, какой бы метод ты не использовал. Если ты не хочешь их обрабатывать, никто тебя не заставит этого делать вне зависимости от способа вызова.

Все еще не вижу ни одного преимущества.

morse ★★★★★
()
Ответ на: комментарий от Deleted

Ох, ну да, моя вина)

Нужно было уточнить, что не только system(), а любое решение из popen, system, exec... VS нативное API библиотеки.

winston3d
() автор топика
Ответ на: комментарий от Crocodoom

Возможны пробелы в имени.

А одинарные кавычки? А знак доллара после одинарной кавычки?

Без зависимостей, очевидно, не обойтись, потому что в стандартной библиотеке работа с файлами и директориями минимальна. Один из вариантов - boost.

anonymous
()
Ответ на: комментарий от DELIRIUM

А программы стартуют без сисколлов?

anonymous
()
Ответ на: комментарий от zudwa

бэкенд обычно полнофункциональное по

Нет. Фронтенд отвечает за взаимодействие с пользователем, бэкенд отвечает за реализацию. Про полнофункциональность ни слова. Вся реализация находится в libcurl, а curl просто представляет для неё консольный интерфейс.

redgremlin ★★★★★
()

библиотеку cURL

Библиотека - правильный вариант. Какие могут быть сомнения?

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от redgremlin

Я не говорю, что дольше разрабатывать. Мой основной тезис: «Не используй system там, где можно использовать либу».

Aswed ★★★★★
()
Ответ на: комментарий от anonymous

есть отдельный котёл в аду для тех, кто подгружает целый boost (либо другой крупный фреймворк) ради одной функции или советует кому то так делать

eternal_sorrow ★★★★★
()
Ответ на: комментарий от redgremlin

ваша мысль понятна, но библиотека не является бэкендом.

Например, никто не считает ангуляр или реакт бекендом для браузерного приложения. А fcgi между сервером и пхп - фронтендом серверного.

А вот интерфейс между клиентским интерфейсом в gui и командной строкой утилиты вполне можно охарактеризовать как фронтенд-бэкенд

zudwa
()
Ответ на: комментарий от Crocodoom

Лаконично и понятно.

Говнокод с инъекцией.

Как бы переписать это место?

Разбить путь на компоненты и вызвать mkdir(3) в цикле. Для выдачи ошибок использовать исключение <system_error> и добавить перегруженную сигнатуру с аргументом error_code& для варианта без исключений.

d_a ★★★★★
()

Если тебе нꙋжно что҃то простое срочно сваѧть на коленке то через system() быстрее. Но это не будет работать если нужно что-то не такое уже и простое.

cvv ★★★★★
()
Ответ на: комментарий от eternal_sorrow

большинство библиотек boost это header only libs. И они друг с другом не связаны.

Говорить о том что boost это крупный фреймворк, это явно быть не в теме...

Например

sudo apt install libboost-atomic-dev

НОВЫЕ пакеты, которые будут установлены:
  libboost-atomic-dev
обновлено 0, установлено 1 новых пакетов, для удаления отмечено 0 пакетов, и 0 пакетов не обновлено.
Необходимо скачать 3 104 Б архивов.
После данной операции, объём занятого дискового пространства возрастёт на 10,2 kB.

10 кб. Очень крупный фреймворк...

fsb4000 ★★★★★
()
Ответ на: комментарий от Iron_Bug

почему?

можно подумать, например, IDE с компилятором как-то иначе дружат, и ведь никого еще паяльником не зажарили?

zudwa
()
Ответ на: комментарий от zudwa

при чём тут IDE с компилятором? IDE - это просто оболочка для редактирования кода. компилятор в ней может быть использован любой и он НИКАК ВООБЩЕ к IDE не привязан. задача IDE - работа с кодом. компиляция - не задача IDE. так что это неадекватный пример.

а софт, который, простите, юзает банальный curl через system - за это надо убивать на месте.

Iron_Bug ★★★★★
()

Имей ввиду, что с popen/pipe тебе придется мутить асинхронный/nb io, в том случае, если идет много ввода и вывода в дочерний процесс. Например ты будешь write в stdin процесса, а процесс будет в это время write в stdout. Если не читать потихоньку его stdout, то вы рано или поздно deadlock (зависит от буфера в ядре).

По сабжу: если тебе много разного из юникса надо обернуть в gtk, то очевидно fork/exec, иначе ты освоишь половину всех библиотек и [хреново] перепишешь половину /usr/bin. В одной строке шелла больше мудрости, чем в 10к строк на си.

По поводу «парсить вывод = ад»: напиши под каждую оборачиваемую утилиту шелл-скрипт, который вернет итоги в едином удобном для сишки виде. Там можно будет и sed, и perl, и awk, и весь юникс.

Для просветления и контраста с местными идиологами можешь почитать исходники и трекер какого-нибудь unetbootin, например. Прям твой случай, один в один.

anonymous
()
Ответ на: комментарий от anonymous

*идеологами, опечатка ненамеренная

anonymous
()
Ответ на: комментарий от winston3d

не критично. Или я ошибаюсь?

Запуск группы процессов при отправке файла, ресайзе изображения, фильтрации лога, [раз]упаковке архива составляет 0,0x%.

anonymous
()
Ответ на: комментарий от Iron_Bug

Это самый адекватный пример, тащемта. Когда что-то сложное работает сообща с остальным сложным, решая сложную задачу, и не пилит ради этого сишкин велик.

Мир всю жизнь io-bound, но нет они всю жизнь считают такты, НТЖ?

anonymous
()
Ответ на: комментарий от anonymous

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

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 2)
Ответ на: комментарий от Iron_Bug

«оболочка для редактирования кода» называется «редактор»

А так - некоторые проекты вообще собираются только в IDE ) Спросите про это у некоторых пользователей QtCreator, VS или того же Code::Blocks ;)

Преимущества использования библиотек понятны, но у system, exec, popen тоже есть свои области использования. Например, интерактивные интерфейсы для утилит, которые также должны использоваться в пакетном режиме из командной строки и т.п. В общем, не всегда это так категорически плохо, как вам кажется.

у Qt, например, есть спец. класс QProcess - для написания фронтендов к утилитам с командной строкой. Так что почему бы и нет?

zudwa
()
Ответ на: комментарий от Iron_Bug

Какой проект тебе не приведи, ты назовешь его говнокодом, потому что у тебя такое определение. Один успешный и удобный я уже привел. Искать их долго, снаружи не видно, что они внутри юзают. И не факт, что ты не права.

Давай объективно, в каком *конечном* итоге выражается неправильность сабжевого подхода? Критериями можно выбрать: простоту/ясность реализации, дальнейшую поддержку/изменяемость, бытовую латентность (не замерную в наносекундах, тут все ясно). Два для разработчика, один для юзера.

Мое мнение по exec/sh: ясность сильно выше (exec(do-curl.sh, -x, -y) вместо страницы-другой кода), поддержка тривиальная (добавить/заменить ключи, изменить регэкс), для юзера может быть небольшая задержка, если комп чем-то серьезным занят.

anonymous
()

странно что такой вопрос вообще возник.

sniper21 ★★★★★
()
Ответ на: комментарий от KennyMinigun

Ну вот и получается, что

  • либо надо завязываться Boost или C++17, что далеко не всегда возможно
  • либо использовать небезопасный system
  • либо вручную мудохаться с разбором пути, тогда получится портянка типа этой (и ещё не факт, что там все особые случаи учтены).
Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Еще можно сделать fork() || execl("/bin/mkdir", "mkdir", "-p", path.c_str(), nullptr); и никаких инъекций.

deadNightTiger ★★★★★
()
Ответ на: комментарий от Crocodoom

Неподъёмной сложности задача?

static void makePath(std::string path, mode_t mode = 0755)
{
    CXX_VALIDATE_ARG(!path.empty());

    if (path[path.size() - 1] != '/')
        path += '/';

    size_t pre = 0, pos = std::string::npos;
    while ((pos = path.find_first_of('/', pre)) != std::string::npos)
    {
        std::string dir = path.substr(0, pos++);
        pre             = pos;

        if (dir.size() == 0)
            continue;

        if ((::mkdir(dir.c_str(), mode) == -1) && errno != EEXIST)
            throw std::system_error{errno, std::generic_category()};
    }
}

(см. тж. Использование system() VS Использование библиотек (комментарий), там правда с обработкой ошибок, сигналов и зомби столько же займёт).

d_a ★★★★★
()
Ответ на: комментарий от anonymous

неправильность выражается в том, что единственное обоснование для внешних вызовов есть сменяемость вызываемого сабжа. скажем, если ты можешь сменить редактор кода в IDE, или компилятор - тогда их, естественно, не нужно вкомпилять. но если у утилиты ничего не меняется и она вызывает банальный curl через жопу - за это надо анально карать паяльником.

Iron_Bug ★★★★★
()
Ответ на: комментарий от zudwa

я юзаю Code::Blocks уже лет десять, если не больше. и он спокойно экспортирует makefile'ы (а также кучу прочих форматов). и может также работать с кастомными makefile'ами. и импортировать какие-то другие форматы проектов (это я не юзаю). он работает с любыми компиляторами, я даже ассемблер на нём собирала и прошивки для микроконтроллеров. это именно удобный инструмент для работы с кодом, с кучей плагинов. и он никак вообще не привязан к компилятору и тулчейну. собственно, даже редактор кода в нём можно выбирать. проекты Code::Blocks прекрасно собираются и без него. и есть отдельные утилиты по экспортированию их во что угодно. никаких чудес в нём нет.

VS - копроративное поделие мелкософта. они в принципе не дают туда вклиниться никому. у них даже дебаггер намертво привязан к студии. хотя много лет назад это было не так и можно было юзать их дебаггер из любых программ. они намеренно делают монолит, чтобы подавить любую конкуренцию. и то он вроде умеет что-то там экспортировать и импортировать.

культя - это отдельная песня. они придумали велосипед с треугольными колёсами и на этом велосипеде невозможно ездить без специальных приспособ типа очень жёстко завязанного на его особенности IDE. но это ущербность самой культи. тот же wxWidgets спокойно позволяет писать проекты без всяких специальных IDE. потому что не обвешан жиром со всех сторон.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.