2017-01-11 53 views
6

Mam krótką tablicę w języku C# i muszę przekonwertować dwa elementy w Int32. To kod pisze się następującoKonwertuj krótki [2] na Int32 w C#

uint pesoparz = (Convert.ToUInt16(values[0])); 
Int32 pesotot = Convert.ToInt32(pesoparz *65536 + Convert.ToUInt16(values[1])); 

gdzie wartości [] jest krótki Array pesotot jest Int32 które I jak do uzyskania. Działa, ale niestety, gdy wartość [1] przekracza 2^15, pojawia się wyjątek przepełnienia systemu.

Dlaczego występuje wyjątek?

+1

użycie 'uncheck' aby uzyskać wokół niego. – Bauss

+0

@Bauss Dobrze, że powierzchownie naprawia oprogramowanie, ale obliczenia wciąż nie są tak pożądane. – Codor

+1

Rozszerzenie znaku prawdopodobnie powoduje błąd. Spróbuj: uint pesoparz = ((wartości [1] i 0xFFFF) << 16) | (wartości [0] i 0xFFFF); – jdweng

Odpowiedz

2

szukasz unchecked który wyłącza IntegerOverflow:

short left = -123; 
    short right = -456; 

    int result = unchecked(BitConverter.IsLittleEndian 
    ? (UInt16)left << 16 | (UInt16)right 
    : (UInt16)right << 16 | (UInt16)left); 

Użytkownik może chcesz użyć BitConverter.IsLittleEndian, aby wykryć kolejność, w której części short powinny zostać połączone w int.

0

Najlepiej użyć shift i czy do tego, i używać unchecked celu uniknięcia błędu przepełnienia:

int result = unchecked((int)(((uint)values[0] << 16) | values[1])); 
0

spróbować

uint pesoparz = (Convert.ToUInt16(values[0])); 
Int32 pesotot = Convert.ToInt32(pesoparz *65536 + Convert.ToUInt32(values[1])); 

Wydaje jesteś osiągnięciu limitu

0
short[] arr = new short[] { 512, -32767 }; 

int ival = ((int)arr[0] * 65536) + ((int)arr[1] & 0xffff); 
// also: 
// ival = ((int)arr[0] << 16) | ((int)arr[1] & 0xffff); 
Console.WriteLine(ival); 

Daje prawidłowy wynik 33587201. Sztuką, jeśli taka istnieje, jest użycie rzucania, aby uzyskać szorty do intów, a następnie maskowanie części, których nie chcesz (w tym przypadku rozszerzenia znaku). To nie wymaga ani Convert ani unchecked.

2

Można używać operatorów bitowe:

short[] parts = new short[2]; 
parts[0] = 1; 
parts[1] = 2; 

uint result = 0; 

result = (ushort)parts[0] << 16 | (ushort)parts[1]; 

Rezultatem będzie 0x00010002 w hex lub 65538 w systemie dziesiętnym.

0

Czy jesteś pewien, że każda wartość twojej tablicy wartości mieści się w klasie Int16?

Jeśli nie, to nawet jeśli odznaczysz się, wynik nie jest tym, czego potrzebujesz. Najpierw musisz zdecydować, co zrobić, jeśli wartości [0] lub wartości 1 są większe niż pasują w klasie Int16.

Twoja decyzja zależy od tego, co oznaczają wartości. Czy wartości [0] reprezentują najwyższe 16 bitów wynikowego Int32 i wartości [0] najniższych 16 bitów?

W takim przypadku należy rzucić wyjątek ArgumentException, jeśli wartości [0] lub wartości 1 jest większa niż Int16.MaxValue. Po, że kod jest proste:

if (values[0] > Int16.MaxValue || values[1] > Int16.MaxValue) 
    throw new ArgumentException("values should fit in two bytes"); 
Int32 result = values[0] << 0x10000 + values[1]; 
return result; 

Może to również oznaczać, że jest to dozwolone, że obie wartości są więcej niż 0x10000, należy myśleć o sobie, co chcesz w wyniku jeśli numery są zbyt duże.

Nawiasem mówiąc, jeśli wartości reprezentują połowę wartości Int32, należy rozważyć zmianę znaczenia wartości [0] i wartości 1. Prawie zawsze najmniej znaczące bity (LSB) są w [0], podczas gdy najbardziej znaczące bity (MSB) są w 1.Jeśli zastosujemy się do tej konwencji, nie trzeba pisać tych konwerterów siebie, można użyć BitConverter class

Int32 original = 0x12345678; 
byte[] bytes = BitConverter.GetBytes(original); 
foreach (var b in bytes) 
    Console.WriteLine(b.ToString("02X"); // write in two digit hex format 
// will write lines with 78 56 34 12 
Int16[] Values = new Int16[] 
{ 
    BitConverter.ToInt16(bytes),  // LSB 
    BitConverter.ToInt16(bytes, 2), // MSB 
}; 
Int32 result = (Int32)values[0] + (Int32)values[1] << 0x10000; 
Debug.Assert(original == result);