2010-10-12 5 views
2

Я пытаюсь создать свойство, которое сделает указатель (byte *) из моего байтового массива (byte []), это действительно работает, однако всякий раз, когда я изменяю этот возвращенный указатель, массив байтов не будет изменен, это часть кода, который я хочу использовать.A byte [] to byte * property

public unsafe class PacketWriter 
{ 
    private readonly byte[] _packet; 
    private int _position; 

    public byte* Pointer 
    { 
     get 
     { 
      fixed (byte* pointer = _packet) 
       return pointer; 
     } 
    } 

    public PacketWriter(int packetLength) 
    { 
     _packet = new byte[packetLength]; 
    } 

    //An example function 
    public void WriteInt16(short value) 
    { 
     if (value > Int16.MaxValue) 
      throw new Exception("PacketWriter: You cannot write " + value + " to a Int16."); 
     *((short*)(Pointer + _position)) = (short) value; 
     _position += 2; 
    } 

    //I would call this function to get the array. 
    public byte[] GetPacket 
    { 
     get { return _packet; } 
    } 
} 

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

+1

Почему вы делаете это вместо простого использования обычного массива? –

+1

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

+0

Мне просто показалось, что вы пишете код, который, скорее всего, будет использоваться для сетевого общения, где вы, вероятно, захотите сохранить порядок байтов в сети. В этом случае я рекомендую использовать BinaryReader и BinaryWriter в MemoryStream, так как они позволяют указать конечную кодировку. Оба предлагаемого кода и BitConverter будут использовать конечную платформу. –

ответ

6

Использование указателей здесь (в C#) бессмысленно.

Обратите внимание, что если вы замените Pointer свойство с

public byte[] Data { get { return _packet; } } 

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

И еще один совет, в вашем Написать16 используйте:

byte[] data = BitConverter.GetBytes(value); 
data.CopyTo(_packet, _positiion); 
_position += data.Length; 
+0

+1, BitConverter - это самый чистый и наиболее безопасный для платформы способ записи эквивалентов байтов в массив (он использует конечную платформу). –

2

Когда ваш элемент управления покидает fixed (и он делает это сразу после возвращения), ваш объект больше не закреплен. Так что это действительно только внутри fixed

+0

@ Andrey, Есть ли другой способ достичь моей цели? – Basser

+0

@Basser использует C++ :) вы должны использовать 'fixed' в области функций. Доступ к собственности не будет работать. я не вижу причин использовать 'byte * 'здесь, указатели являются исключительными в C# и требуют исключительных ситуаций. Это, безусловно, нет. – Andrey

+0

@Basser, какова ваша цель? Что вы хотите сделать с указателем? – testalino

0

Если вы имеете дело с управляемой памятью, то да, вы должны ограничить ее до блока fixed.

КУПИТЬ Кажется, что вы используете много обработки указателей, и мой вопрос - почему вам нужна управляемая память? Просто выделите некоторую неуправляемую память, используя Marshal.AllocHGlobal(), а затем выведите ее как указатель. Вам просто нужно убедиться, что вы выпускаете его в Dispose().

2

Не подвергайте указатели. Вы упреждаете оптимизацию своего кода. Чтобы дать вам пример, я написал PNG-декодер в C# для проекта, над которым я работаю, и вместо того, чтобы предполагать, что узкие места я написал код, чтобы сделать управление структурами данных тривиальным и был довольно blithe о I/O и данных движение. При анализе кода узкие места были НЕ в движении данных или в I/O, но находились в предсказании Paeth - вычислении, которое выполнялось по-пиксельной основе (подробности here).

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

1

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

Если вам действительно нужно сэкономить несколько тактовых циклов (при дороговизной стоимости уменьшенной ремонтопригодности), либо создайте неуправляемую DLL на C++ для обработки высокопроизводительных требований, либо напишите чистый небезопасный код, работающий исключительно на неуправляемой памяти с маршалом. Фактически, маршал уже имеет метод WriteInt16, который вы можете использовать.Накладные расходы на маршалинг обратно в управляемую память будут относительно высокими, однако (намного выше, чем бит-маскирование), поэтому это полезно только в том случае, если вы пишете очень большой объем памяти в чрезвычайно внутреннем цикле и делаете другие операции с ним, кроме простого копирования (так как в любом случае ему придется копировать в управляемую память для маршала).