2017-02-22 7 views
2

Я хочу создать тест C# sqrt, но некоторые функции sqrt требуют объединения для побитового вычисления.неназначенное поле в явном строчном макете

Мой союз определяется как это:

[StructLayout(LayoutKind.Explicit)] 
struct U 
{ 
    [FieldOffset(0)] 
    public int i; 
    [FieldOffset(0)] 
    public float x; 
} 

и следующий код выдает незадействованную ошибку поля на u.i:

U u; 
u.x = x; 
u.i = (1 << 29) + (u.i >> 1) - (1 << 22); 

Я знаю, пользовательский интерфейс был назначен, когда УБ также назначается, так это можно игнорировать непризнанную ошибку поля во время компиляции без явного назначения u.i?

+1

Нет, вы не можете игнорировать. Просто добавьте его. Однако ... почему вы хотите, чтобы _emulate_ union в C#?!?! Работая с удвоениями, вы можете использовать битконвертер. С поплавками ... ну для теста я бы оставил назначение и просто вычислил 'sqrt()', дополнительное назначение для 'u.i' не будет измерено. Если вы действительно хотите это сделать, то идите медленным путем: http://stackoverflow.com/q/21801213/1207195 –

+0

@AdrianoRepetti primary C function as union Я просто хочу реплицировать как C (ish), насколько это возможно. BitConverter кажется медленнее, чем базовый «эмулируемый»? но если это неправильно, я буду использовать его. Кстати, я согласен на дополнительное задание. –

+0

Отметьте связанное сообщение, в принятом ответе есть доступ к памяти 'unsafe', должен быть таким же быстрым, как C' union' –

ответ

2

FieldOffset - это функция взаимодействия, а не то, что должно повлиять на управляемый код. Нет гарантии (или требования), чтобы фактическая компоновка структуры на управляемой стороне заложила i по той же памяти, что и x. Макет, в котором есть два полностью отдельных поля, будет абсолютно корректным, если он перемещается в одно и то же место памяти при выполнении взаимодействия. Тот факт, что ваша среда выполнения на вашем компьютере, в частности, делает, перекрывает два поля, на что вы не должны полагаться, и это только оптимизация производительности, деталь реализации.

Если вы хотите выполнять неуправляемые операции, подобные этому, используйте небезопасный код. Вот для чего это. Не злоупотребляйте функциями взаимодействия. И, конечно же, не ожидайте, что он будет портативным.

float x = 42.0f; 

(*(int*)((void*)&x)) // The value of `x` reinterpreted as an int 

Полный пример вашего приближения может выглядеть квадратный корень что-то вроде этого:

unsafe void Main() 
{ 
    sqrt(42).Dump(); // 6.625 
    sqrt(9).Dump(); // 3.125 
} 

unsafe float sqrt(float x) 
{ 
    int* pX = (int*)((void*)&x); 

    *pX = (1 << 29) + (*pX >> 1) - (1 << 22); 

    return x; 
} 
+0

Я не думаю, что правильно сказать, что «управляемая сторона будет класть' i' над той же памятью, что и 'x '' Развернутая структура структуры используется для выполнения интерполяции путем позиционирования битов, и в вашем случае это не сработает. Ваш '(int *) ((void *) &x);' переведен на '(int *) & x' на IL-код, но вы правы, это кажется быстрее, чем с помощью struct, я буду сканировать оба. Спасибо @Luaan! –

+1

@ FlorianJ Я написал, что у вас нет никакой гарантии, что это произойдет, т. Е. Противоположно тому, что вы прочитали :) 'StructLayout' (и' FieldOffset') для взаимодействия - любое изменение, которое они делают для управляемого макета памяти, является деталью реализации, а не чем-то вы можете положиться. Точно так же безопасно взять указатель на поле, но не добавлять смещение к этому указателю и ожидать найти другое поле там - это просто не является частью контракта. – Luaan

Смежные вопросы