"Лишнее" в сборках CLR:Pure MC++
Меня некоторое время назад заинтересовал вопрос, почему же сборки сделанные на C# или MC++(CLR:Safe) имеют размер 8кб. А вот сборки сделанные на MC++(CLR:Pure) с тем же кодом имеют размер 24 и более кб.
Вообщем открыл я сборку CLR:Pure ildasm'ом и увидел так кучу всякого кода для взаимодействия царств Native и Clr:
.field static assembly int32 '?Uninitialized@CurrentDomain@<CrtImplementationDetails>@@$$Q2HA'
.custom instance void [mscorlib]System.Runtime.CompilerServices.FixedAddressValueTypeAttribute::.ctor() = ( 01 00 00 00 )
.field static assembly method void *() '?A0x250abb45.?Uninitialized$initializer$@CurrentDomain@<CrtImplementationDetails>@@$$Q2P6MXXZA' at D_000030CC
.field static assembly valuetype '<CppImplementationDetails>'.$ArrayType$$$BY00Q6MPBXXZ modopt([mscorlib]System.Runtime.CompilerServices.IsConst) '?A0x250abb45.__xi_vt_a'/
..................
И рад был бы. Но "C" и "С++" не используется в моем проекте на MC++ в принципе(поэтому надобности в подобном захламлении сборки не вижу). Однако возможность использовать указатели тем не менее очень нужна.
Попытался "исправить" положение. Весь проект составил из одного *.cpp файла и в самом верху(первой же строкой) продекларировал:
#pragma managed
И ничего. Хоть вешайся. Захламления сборки ненужным кодом это не убрало....
Может кто подскажет как это сделать....:confused:
А то руки уже к паре ildasm\ilasm тянуться:(
А чем C# в таком случае не угодил?
Указатели!!!
В C# указатель можно объявить только на Value Type, не являющийся Generic'ом и не содержащий в себе ссылочных типов.
В MC++ архитектура pin_ptr<G> свободно с этим справляется.
В C# указатель можно объявить только на Value Type, не являющийся Generic'ом и не содержащий в себе ссылочных типов.
Вполне разумно. Зачем создавать указатель на ссылочный тип? ;) Но с генериками да, вышел косячокс, впрочим есть замечательный тип GCHandle.
Иногда и на ссылочный нужен.
Допустим конструкция извлекающая jй столбец прямоугольного массива
{
T item;
};
public ref struct Special abstract sealed
{
generic<class T> static array<T>^ GetColumn(array<T,2>^ Array, int j)
{
int n = Array->GetLength(0);
int m = Array->GetLength(1);
array<T>^ Return = gcnew array<T>(n);
pin_ptr<T> p = &Array[0,j];
pin_ptr<T> r = &Return[0];
for(Box<T> *_It = (Box<T>*)r, *_It_end = _It + n, *_It_src = (Box<T>*)p; _It<_It_end; *_It = *_It_src, _It++, _It_src+=m);
return Return;
}
};
На С# ее никак не повторишь.
А через индексаторы это делать - в 2 раза дольше будет.
И что самое приятное совершенно неважно, ссылочный это тип или не ссылочный - все будет работать!
Допустим конструкция извлекающая jй столбец прямоугольного массива
Для получения строки двумерного массива есть обощенный код:
int rows = a.GetLength(0);
int cols = a.GetLength(1);
if (rows <= index)
throw new IndexOutOfRangeException();
T[] result = new T[cols];
int len = Buffer.ByteLength(result);
Buffer.BlockCopy(a, len * index, result, 0, len);
return result;
}
Что-то похожее для получения столбца, признаюсь, не придумал.
З.Ы. Ваш нэйминг - адская жесть.
Который выдает исключение в том случае, если массив содержит не примитивы:
Необработанное исключение: System.ArgumentException: Объект должен быть массивом примитивов.
Имя параметра: src в System.Buffer.BlockCopy(Array src, Int32 srcOffset, Array dst, Int32 dstOffset, Int32 count)
Да еще и проигрывает по скорости обычным индексаторам result[j]=a[index,j]
Да грешу этим.
1) Пишу сборку на C#
2) Критическую функции пишу на MC++
3) dlasm разбираю обе сборки. заменяю несколько функций в Шарповой сборке на @быстрые@ аналоги из функции MC++ сборки
4) собираю сборку
Необработанное исключение: System.ArgumentException: Объект должен быть массивом примитивов.
Имя параметра: src в System.Buffer.BlockCopy(Array src, Int32 srcOffset, Array dst, Int32 dstOffset, Int32 count)
Да еще и проигрывает по скорости обычным индексаторам result[j]=a[index,j]
Признаюсь, не проверял. :(
1) Пишу сборку на C#
2) Критическую функции пишу на MC++
3) dlasm разбираю обе сборки. заменяю несколько функций в Шарповой сборке на @быстрые@ аналоги из функции MC++ сборки
4) собираю сборку
Может быть лучше использовать .net модуль (netmodule) создаваемый MC++, а при компиляции C# проекта подключать его (где-то на форуме я рассказывал, как подключить). Правда, получится не один а два файла в итоге.
А Net модуль на MC++ не утянет с собой "код инфраструктуры MC++"?
Фиг знает.
А разве эти "лишние" 24 КБ сильно мешают?
На С# ее никак не повторишь.
А через индексаторы это делать - в 2 раза дольше будет.
Да нет, не более 12% медленнее, да и то за счёт проверки границ массива во время исполнения.
У меня получилось что на 40%.
Уж не знаю почему, но вот так.
Допускаю из-за того что индексация [i,j] развертвается как:
1) проверка границ
2) (адрес начала массива)+i*(число эл-тов в строке)+j
А в цикле который я привел отсутствует как проверка границ, так и умножение для получения следующего нужного эл-та.
Уж не знаю почему, но вот так.
Допускаю из-за того что индексация [i,j] развертвается как:
1) проверка границ
2) (адрес начала массива)+i*(число эл-тов в строке)+j
А в цикле который я привел отсутствует как проверка границ, так и умножение для получения следующего нужного эл-та.
Проверка в дотнете не учитывает объявленную размерность, проверяется попадание в массив.
Т.е. формула адреса будет примерно такая:
адрес_массива + i * j * размер_элемента
проверка попадания:
i * j < общая_длина
Уж не знаю почему, но вот так.
Ну вот проектец и ложик профайлера.