Comments 41
Спасибо за статью, интересно.
Добавьте раскраску синтаксиса и отступы, а то некоторые примеры становятся плохо понятными.
А как раскраску добавить? Я в тэг code участки кода заключил. По идее при этом оно само и должно было раскрасить…
Или такой, там даже отдельная галочка «для хабра» есть ;)
А какой смысл портировать такие библиотеки под C#, когда есть GDI+? Я понимаю смысл портирования AGG или ещё чего-то такого, но библиотеки для работы с форматами файлов?!
Sergius Bobrovsky:
К сожалению, GDI+ имеет множество ограничений. Самое главное — вся
картинка сразу грузится в память. Как следствие очень большие картинки
просто не открываются. Далеко не все варианты TIFF файлов
поддерживаются GDI+ (это существенно улучшили в Windows 7). Нет
тонкого контроля над способом сохранения данных в файл. Например, до
Windows 7 все файлы сохранялись в один strip (все скан-линии
сохранялись одним блоком). Начиная с Windows 7 все файлы сохраняются
во множество strip-ов (и это неьзя изменить), что тоже плохо, так как
есть ситуации, когда должен быть один strip. И таких тонкостей
достаточно много
А чем плохо сделать интерфейс к С-шной библиотеке и использовать ее методы напрямую?
В общем случае, такой интерфейс может быть достаточен. Но если требуется, чтобы сборка работала в режиме medium trust (этот режим часто установлен на веб-серверах), то такое решение не подойдет, так как в режиме medium trust нельзя использовать unmanaged code.
Хотелось бы просто для саморазвития на будущее узнать: а была ли какая-нибудь проблема вместо замены указателей на функции применить функторы (иерархию функторов) или это просто не стоило того и затраты времени и сил оказались бы сравнимыми или даже больше?
Sergius Bobrovsky:
Можно было применить и функторы, тут вопрос вкуса. Я решил обойтись
без них, чтобы иметь «готовый к переносу» код еще до смены
компилятора.
А как относительно директив препроцессора в C#?
Не извращенные define, конечно, а условная компиляция?
В c# условная компиляция есть. То есть можно при помощи define-ов делать разные сборки из одного кода. Возможно, я не понял вопроса.
Мой вопрос следовало читать в контексте предыдущего: "… а была ли какая-нибудь проблема вместо..." выбрасывания директив препроцессора "… применить..." директивы препроцессора в С#. Тогда все становится на место.
Можно часть директив препроцессора оставить, об этом написано в статье. Но я рекомендую все-таки удалить все директивы, которые используются для создания разных вариантов программы/библиотеки, чтобы облегчить тестирование в процессе переноса.

Если есть необходимость, то можно потом добавить такие директивы снова.
Sergius Bobrovsky:
Наверное, этот вариант позволил бы быстрее решить поставленную задачу,
но, имхо, читабельность кода была бы гораздо ниже. И все равно
некоторое количество рутинных усилий потребовалось бы. И самое
главное, полученный результат нельзя было бы включить в код сборки на
c# (у меня было такое требование). ILMerge я знаю, но это не
подходило.
Мне кажется, кроме академического интереса — толка в этом минимум.
На много проще и правильнее будет написать вреппер на Managed C++
Действительно какая-то странная методика перелопачивания сорцов. Тем более еще не факт, что оно после этого не будет жутко тормозить.
Соглашусь. Несмотря на свою похожесть C++ и C# — это, всё таки, разные языки. И далеко не всегда то, что хорошо работает, будучи написанное на C++, будет также хорошо работать переложенное «1-в-1» на C#.
Конечно, возможна ситуация, что после трансформации код начнет работать медленнее. Об этом и в статье написано. Поэтому описанный способ ни в коем случае не серебрянная пуля.
Все зависит от требований. То есть если нужно сделать простую консольную программу, которая использует стороннюю unmanaged dll, то можно обойтись и p/invoke (даже врэппер никакой не нужен). Если требования другие (например, возможность запуска в medium trust режиме), то и решения требуются другие.

В статье изложен способ трансформации кода, но не затронута тема необходимости такой трансформации. Иногда такая необходимость есть, иногда нет.
А что, вот пусть сам Sergius Bobrovsky бы и написал статью в песочницу, как честные люди поступают
Уж не знаю как у других, но у меня с песочницой дружба «не срослась». У Сергея — тоже. Стати, которые нормально воспринимаются сообществом после получения инфайта, в песочницу или не проходят вообще без объяснения причин, или висят там незаметными. Данная статья из песочницы и есть.
Не знаю как в C#, в Java можно подключать нативные Cшные библиотеки. Зачем городить огород, если можно просто заюзать?
например надо воспользоваться этой библиотекой в silverlight-приложении (ну или java-апплете), а там допускается только managed-код
В c# тоже можно использовать нативные dll. Другое дело, что такой подход имеет свои ограничения: он часто неприменим на веб-серверах (особенно в случае использования shared hosting), для некоторых приложений весьма вероятны проблемы, если идет частый обмен данными большого объема между managed и unmanaged кодом. В Silverlight приложениях такой подход вообще неприменим.

Потому я и описал этот способ, что столкнулся с невозможностью использовать p/invoke или COM Interop.
любопытный эволюционный подход. Постепенно меням под себя. Хоть и не пишу на си-шарпе, но понравилось
Если есть необходимость, то такой подход можно использовать и для трансформации c/c++ => java.
1.
case -1:
if ( line != buf + (bufsize - 1) )
continue;
/* falls through */
default:

на C# будет выглядеть так:
case -1:
if ( line != buf + (bufsize - 1) )
continue;
/* falls through */
goto default;
default:

и не надо ничего мудрить

2. typedef vector<Command*> Commands;
будет выглядеть как:
using Commands = vector<Command*>;
Спасибо за пункт 1). Не знал, что можно использовать goto case x / goto default.

Что касается пункта 2), то тут дело вкуса. Я в статье написал, что такие конструкции «я предпочитаю встраивать». То есть это мой совет/привычка, это не требование.
Найдут уязвимость или просто ошибку в «портированной» библиотеке — кто будет у вас её исправлять? Ведь фактически вы её не портировали, а форкнули.
Все зависит от ситуации. Если портируется собственный код компании (по какой-либо причине), то исправлять ошибку будет та же команда, что писала и оригинальный код. Если же портируется какая-то сторонняя библиотека или программа, то тут надежда только на свои силы / силы тех, кто будет пользоваться новой версией (если это разработчики и новая версия доступна в исходниках).

Поэтому я ни в коем случае не призываю портировать все, до чего дотянутся руки, а лишь описал способ, которым это можно сделать, если такая необходимость есть.
Only those users with full accounts are able to leave comments. Log in, please.