2017-02-06 5 views
3

Я портирую библиотеку с C++ на C#, но столкнулся со сценарием. Я не уверен, как его решить, что связано с литьем unsigned char * на unsigned int *.unsigned char * - Equivalent C#

C++

unsigned int c4; 
unsigned int c2; 
unsigned int h4; 

int pos(unsigned char *p) 
{ 
    c4 = *(reinterpret_cast<unsigned int *>(p - 4)); 
    c2 = *(reinterpret_cast<unsigned short *>(p - 2)); 
    h4 = ((c4 >> 11)^c4) & (N4 - 1); 

    if ((tab4[h4][0] != 0) && (tab4[h4][1] == c4)) 
    { 
     c = 256; 
     return (tab4[h4][0]); 
    } 

    c = 257; 
    return (tab2[c2]); 
} 

C# (это не так):

public uint pos(byte p) 
{ 
     c4 = (uint)(p - 4); 
     c2 = (ushort)(p - 2); 
     h4 = ((c4 >> 11)^c4) & (1 << 20 - 1); 
     if ((tab4[h4, 0] != 0) && (tab4[h4, 1] == c4)) { 
      c = 256; 
      return (tab4[h4, 0]); 
     } 
     c = 257; 
     return (tab2[c2]); 
} 

Я верю в C# Например, вы могли бы изменить byte p к byte[] но я невежествен, когда он придет литьем byte[] к одно значение uint.

Кроме того, может ли кто-нибудь объяснить мне, почему вы сделали бы unsigned char *unsigned int *? Какую цель он имеет?

Любая помощь/толчок к направлению будет очень полезной.

+0

Арифметика указателя, которая происходит с p-4 и p-2, потребует рассмотрения контекста вызова, прежде чем мы сможем даже попытаться определить правильную подпись для эквивалента C#. Какова структура памяти 'p' в источнике? – dlatikay

+2

Вы можете использовать класс BitConverter. – bitbonk

+0

использовать C++/CLI и оставить свой существующий код C++ как есть –

ответ

3

Перевод проблемных линий будет:

int pos(byte[] a, int offset) 
{ 
    // Read the four bytes immediately preceding offset 
    c4 = BitConverter.ToUInt32(a, offset - 4); 
    // Read the two bytes immediately preceding offset 
    c2 = BitConverter.ToUInt16(a, offset - 2); 

и изменить вызов от x = pos(&buf[i]) (который даже в C++ такой же, как x = pos(buf + i)) до

x = pos(buf, i); 

Важно отметить, что существующий код на C++ неверен, так как он нарушает правило строгого сглаживания.

+0

Я просто прекратил публиковать свой собственный ответ, когда заметил, что в архитектуре, где 'int' в C++ будет 32-битной шириной, мы имеем перекрытие. в этом случае c2 не просто будет нижним словом c4? – dlatikay

+0

@dlatikay: Да, это накладывается. Также в коде на C++. (На архитектурах, где используется C#, 'c2' будет более высоким словом, а не ниже, но ваше наблюдение в основном правильное) –

+0

Прекрасное чистое решение. Спасибо! Кроме того, @dlatika благодарю вас за вашу помощь. –

0

В коде C++ вы отправляете указатель на char, но, как правило, C# не работает с памятью таким образом, вам нужен массив вместо указателя.

Но вы можете использовать ключевое слово unsafe для работы непосредственно с памятью. https://msdn.microsoft.com/en-us/library/chfa2zb8.aspx

1

Внедрение аналогичной функциональности в C# не обязательно должно включать код, который реплицирует версию C на основе выводов, особенно когда оригинал использует указатели.
Когда мы предполагаем архитектуру, где int является 32 бит, вы могли бы упростить C# версии, как это:

uint[] tab2; 
uint[,] tab4; 
ushort c; 

public uint pos(uint c4) 
{ 
    var h4 = ((c4 >> 11)^c4) & (1 << 20 - 1); 
    if ((tab4[h4, 0] != 0) && (tab4[h4, 1] == c4)) 
    { 
     c = 256; 
     return (tab4[h4, 0]); 
    } 
    else 
    { 
     c = 257; 
     var c2 = (c4 >> 16) & 0xffff; // HIWORD 
     return (tab2[c2]); 
    } 
} 

Это упрощение возможно потому, что с4 и с2 перекрытия: c2 является высокое слово с4, и требуется только когда поиск в tab4 не соответствует.

(Идентификатор N4 присутствовал в исходном коде, но заменен в вашем собственном переводе выражением 1 < < 20).

Вызывающий код должен был бы перебирать массив из int, который согласно комментариям возможен. Хотя исходный код C++ начинается со смещения 4 и оглядывается назад, эквивалент C# начинается со смещения 0, что кажется более естественным.

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