6 Nibble signed Hex-String korrekt anzeigen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von exc-jdbi.

    6 Nibble signed Hex-String korrekt anzeigen

    Hallo zusammen,
    ich habe einen String der einen 6 Nibble langen hexadezimalen Wert enthält, z.B. "123456" (positiver Wert) oder "876543" (negativer Wert).
    Diesen möchte ich nun in einem Label vorzeichenrichtig als signed Integer ausgeben.
    Bei einem 4 Nibbel String mache ich das so:

    VB.NET-Quellcode

    1. Dim _i1 As Short = Convert.ToInt16("8111", 16) '_i1 = 8111
    2. Dim _i2 As Integer = Convert.ToInt32(_i1) '_i2 = FFFF8111
    3. Dim _s1 As String = _i2.ToString '_s1 = -32495

    Wie bekomme ich das aber bei einem 6 Nibble HexWert hin?
    Ich müsste den String ja zunächst vorzeichenrichtig auf 8 Nibble erweiteren, aber wie?
    Und vorallem suche ich eine Möglichkeit diese Berechnung allgemein für Strings mit Längen <> 4, 8, 16 durchzuführen.
    Convert.ToInt32("8111", 16) gibt 33041
    Convert.ToInt16("8111", 16) gibt -32495

    Da 008111 aber dasselbe ist wie 8111, ist hier natürlich die Frage warum das eine für dich richtig ist und das andere falsch. (Deswegen kommt bei 876543 auch kein negativer Wert)
    Welche Einschränkung muss auf der resultierende Datentypgröße gemacht werden?

    Bzw. hast du eine genaue Bitvorschrift für dein Ergebnis? Soll das ein 4*String.Length Bit Integer werden? Das wäre aber kein klassischer signed integer, die sind halt 32 bit lang

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Warum rechnest du bitte in Nibble? Ergibt doch gar keinen Sinn; kann kaum ein System was mit anfangen.
    Die meisten ISAs sind auf Byte-Ebene unterwegs und das solltest du auch sein.

    Du hast also ein 3-Byte Wert.
    Dementsprechend gehört das in ein (minimum) 4 Byte Integer.

    Mehr musst du auch gar nicht machen... Der Compiler bzw. die Runtime wird das für dich erledigen.

    Hier mal ein Beispiel (in C++ wegen dem Union, aber ist in VB/C# sehr ähnlich).

    C-Quellcode

    1. #include <cstdint>
    2. #include <iostream>
    3. union AUnionForDifferentIntegerLengths {
    4. uint8_t byte;
    5. int8_t sbyte;
    6. uint16_t ushort;
    7. int16_t short_;
    8. uint32_t uint;
    9. int32_t int_;
    10. uint64_t ulong;
    11. int64_t long_;
    12. };
    13. int main() {
    14. AUnionForDifferentIntegerLengths u{};
    15. u.ulong = 0x876543;
    16. printf("u.ulong = 0x%lx = %lu => \"%s\"\n", u.ulong, u.ulong, std::to_string(u.ulong).c_str());
    17. printf("u.long_ = 0x%lx = %ld => \"%s\"\n", u.long_, u.long_, std::to_string(u.long_).c_str());
    18. printf("u.uint = 0x%x = %u => \"%s\"\n", u.uint, u.uint, std::to_string(u.uint).c_str());
    19. printf("u.int_ = 0x%x = %d => \"%s\"\n", u.int_, u.int_, std::to_string(u.int_).c_str());
    20. printf("u.ushort= 0x%x = %u => \"%s\"\n", u.ushort, u.ushort, std::to_string(u.ushort).c_str());
    21. printf("u.short_= 0x%x = %d => \"%s\"\n", u.short_, u.short_, std::to_string(u.short_).c_str());
    22. printf("u.byte = 0x%x = %u => \"%s\"\n", u.byte, u.byte, std::to_string(u.byte).c_str());
    23. printf("u.sbyte = 0x%x = %d => \"%s\"\n", u.sbyte, u.sbyte, std::to_string(u.sbyte).c_str());
    24. }


    Compilerbefehl: g++ -ointtest test.cpp
    Ausgeführt mit: ./inttest

    Ausgabe:

    Quellcode

    1. u.ulong = 0x876543 = 8873283 => "8873283"
    2. u.long_ = 0x876543 = 8873283 => "8873283"
    3. u.uint = 0x876543 = 8873283 => "8873283"
    4. u.int_ = 0x876543 = 8873283 => "8873283"
    5. u.ushort= 0x6543 = 25923 => "25923"
    6. u.short_= 0x6543 = 25923 => "25923"
    7. u.byte = 0x43 = 67 => "67"
    8. u.sbyte = 0x43 = 67 => "67"


    Wie du siehst, wird der Wert automatisch vom Compiler bzw. der Runtime bei dynamischen Zahlen angepasst. Geht ja auch nicht anders. Computer arbeiten nunmal mit Zweierpotenzen.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.
    Hallo zusammen,
    @siycah ich rechne nicht in Nibbeln, ich bekomme diese als Daten.
    Die Register im Zielsystem haben unterschiedliche Tiefen, manche sind 1, 2, 4, 6, 8... Byte, oder was auch immer tief.
    Lese ich so ein Register kommt der gelesne Wert als "String" und ist eben 2, 4, 6, 8... Nibble lang.
    Diesen Wert muss ich anzeigen, aber eben nciht Hex, so wie kommt, sondern als Integer, daher die Umrechnung.
    Ich mache mit 24 Bit (6 Nibble) Strings jetzt folgendes:
    -ich wandle nach Integer
    -teste auf > 2^23 => wenn ja, dann ist der Wert negativ, andernfalls positiv
    Schreibe mir das gerade als allgemeingültige Funktion, egal wie lang der String ist.



    VB.NET-Quellcode

    1. 'ConvertHexValStringToSignedIntString(): wandelt einen hexadezimal String mit der Länge 1..8 in einen String um,
    2. ' der den Übergabestring als sigend Integer ausgibt.
    3. Private Function ConvertHexValStringToSignedIntString(s As String) As String
    4. Dim _iLength As Integer
    5. Dim _sReturn As String = String.Empty
    6. Dim _iSubtrahend As Integer = Convert.ToInt32(s, 16)
    7. If s IsNot String.Empty Then
    8. _iLength = s.Length
    9. If _iLength > 8 Then
    10. Return _sReturn
    11. End If
    12. Else
    13. Return _sReturn
    14. End If
    15. '2 Nibble => 2^7 => _iSub = "000000FF"
    16. '4 Nibble => 2^15 => _iSub = "0000FFFF"
    17. '6 Nibble => 2^23 => _iSub = "00FFFFFF"
    18. '8 Nibble => 2^31 => _iSub = "FFFFFFFF"
    19. If _iSubtrahend >= 2 ^ ((_iLength * 4) - 1) Then
    20. 'Wert negativ
    21. Dim _sMinuend As String = String.Empty
    22. Dim _iMinuend As Integer = Convert.ToInt32(_sMinuend.PadRight(_iLength, "F"c), 16)
    23. _sReturn = "-" & (_iMinuend - _iSubtrahend + 1).ToString
    24. Else
    25. _sReturn = _iSubtrahend.ToString
    26. End If
    27. Return _sReturn
    28. 's = "8000" => _sReturn = "-32768"
    29. 's = "FFFF" => _sReturn = "-1"
    30. 's = "FFFD" => _sReturn = "-3"
    31. 's = "1234" => _sReturn = "4660"
    32. 's = "8765" => _sReturn = "-30875"
    33. 's = "123456" => _sReturn = "1193046"
    34. 's = "876543" => _sReturn = "-7903933"
    35. 's = "12345678" => _sReturn = "305419896"
    36. 's = "87654321" => _sReturn = "-2023406815"
    37. End Function


    Beiträge zusammengefügt. ~Thunderbolt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Thunderbolt“ ()

    Heißt ja noch lange nicht, dass ein 6 Nibble tiefes Register auch einen 24-bit Integer repräsentieren soll, für uns wirkt daher dein Präsentation als willkürlich.
    Wem auch immer du die Zahl -7903933 in die Hand gibts, da wird der ne Weile nicht drauf kommen.

    Hier der Trick:

    VB.NET-Quellcode

    1. Dim input = "876543"
    2. Dim regularLong = Convert.ToInt64(input, 16) ' is 8873283
    3. Dim test = CLng(1) << (input.Length * 4 - 1)
    4. Dim weirdlong = regularLong
    5. If test <= regularLong Then ' regular ist zu groß für input.Length
    6. Dim mask = ((CLng(1) << (64 - input.Length * 4)) - 1) << (input.Length * 4) ' das sind die negativen 1en am Ende für die Konversion.
    7. Dim weirdLong = mask + regularLong ' is -7903933
    8. End If

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Bei uns im System sind die Registertiefen fest definiert. Es gibt 16 Bit signed und unsigned hex, genau wie 24 Bit signed und unsigend hex.
    Die Inhalte werden IMMER als String gelesen dessen Daten IMMER der Registertiefe entsprechen und stellen i.d.R. Messwerte dar.
    Somit ist klar, lese ich ein 16 Bit Rgister ist dieser Wert sicher max. 2^16 und ebenso 2^24 bei einem 24 Bit Register.
    Normalerweise werden diese NIE als signed/unsigend Integer interpretiert, sondern sind ADC/DAC Werte die nach dem Lesen einfach in Integer gewandelt und mit Bitwertigkeiten multiplizeiert werden.
    Da stellte sich nie die Frage der Darstellung des Rohwertes als signed/unsigend integer, wie es jetzt in eine Ausnamhe doch der Fall ist. Daher bin ich überhaupt über dieses Problem gestolpert.
    Das die Daten als String kommen ist bei uns historisch. Wir nutzen eine Art Telnet Code in ASCII zum besseren Klartextlesen der Daten. Daher dieses "komische" Format.
    Deinen Code probiere ich nächste Woche gerne mal aus. Danke dafür.
    Hab mal was ganz verrücktes gemacht.

    Wollte wissen, ob man einen Pointer so gestalten kann, dass er genau diesen Anforderungen standhält. Die Lösung ist sehr einfach. Man macht einen Pointer der alle gewünschte Pointer-Ranges beinhaltet. Also einen für 16, einen für 24 und einen für 32. Der kleine Vorteil hier ist, man kann eine Byte-Strecke direkt mit dem Pointer durchlaufen, und erhält alle gewünschten Angaben.

    Vielleicht kann es ja jemand gebrauchen.

    Freundliche Grüsse

    exc-jdbi

    Samples

    C#-Quellcode

    1. private static void Samples1()
    2. {
    3. //s = "FFFF" => _sReturn = "-1"
    4. //s = "FFFD" => _sReturn = "-3"
    5. //s = "1234" => _sReturn = "4660"
    6. //s = "8765" => _sReturn = "-30875"
    7. //s = "123456" => _sReturn = "1193046"
    8. //s = "876543" => _sReturn = "-7903933"
    9. //s = "12345678" => _sReturn = "305419896"
    10. //s = "87654321" => _sReturn = "-2023406815"
    11. var sz1 = Unsafe.SizeOf<Int32_24_16>();
    12. var sz2 = Marshal.SizeOf<Int32_24_16>();
    13. var i0 = new Int32_24_16("FFFF");
    14. var str = i0.ToString();
    15. var i1 = new Int32_24_16("FFFD");
    16. var i2 = new Int32_24_16("1234");
    17. var i3 = new Int32_24_16("8765");
    18. var i4 = new Int32_24_16("123456");
    19. var i5 = new Int32_24_16("876543");
    20. var i6 = new Int32_24_16("12345678");
    21. var i7 = new Int32_24_16("87654321");
    22. var i8 = new Int32_24_16("94989234");
    23. var i9 = new Int32_24_16("91888630");
    24. var i10 = new Int32_24_16("91821327");
    25. var i11 = new Int32_24_16(i6);
    26. var i12 = new Int32_24_16(i8.AsInteger());
    27. }
    28. private unsafe static void Samples2()
    29. {
    30. var rand = Random.Shared;
    31. var size = rand.Next(10, 65);
    32. if (int.IsOddInteger(size)) size--;
    33. var tmp = new byte[size];
    34. rand.NextBytes(tmp);
    35. var hex = Convert.ToHexString(tmp);
    36. var tsz = Unsafe.SizeOf<Int32_24_16>();
    37. var i32xs = new Int32_24_16[hex.Length / tsz / 2];
    38. var bytes = Convert.FromHexString(hex);
    39. var str = string.Empty;
    40. fixed (byte* ptr_bytes = bytes)
    41. fixed (Int32_24_16* ptr_i32x = i32xs)
    42. for (int i = 0; i < bytes.Length; i += tsz)
    43. {
    44. var ptr = (Int32_24_16*)(ptr_bytes + i);
    45. *(ptr_i32x + i / tsz) = *ptr; //See variable i32xs
    46. var h = (*(ptr_i32x + i / tsz)).ToHex();
    47. str += h;
    48. }
    49. //The results can be found in the variable 'i32xs'.
    50. //The pointer functions here as a simple "caster",
    51. //which is iterated over the array of byte.
    52. }

    Pointer

    C#-Quellcode

    1. using System.Runtime.InteropServices;
    2. using System.Runtime.CompilerServices;
    3. using System.Diagnostics.CodeAnalysis;
    4. namespace exc.jdbi.Pointers;
    5. [StructLayout(LayoutKind.Explicit)]
    6. public readonly struct Int32_24_16
    7. {
    8. [FieldOffset(0)]
    9. private readonly I24 V0;
    10. [FieldOffset(3)]
    11. private readonly byte V3 = 0;
    12. public static Int32_24_16 Zero => new();
    13. public bool IsZero => this.V0.IsZero && this.V3 == 0;
    14. public Int32_24_16(string hex)
    15. {
    16. var str_hex = hex.Length > 8 ? hex[..8] : hex;
    17. var bytes = Convert.FromHexString(str_hex);
    18. Array.Reverse(bytes);
    19. this.V0 = new I24(bytes, 0);
    20. if (bytes.Length > 3) this.V3 = bytes[3];
    21. }
    22. public Int32_24_16(string hex, int start_idx)
    23. : this(hex[start_idx..])
    24. {
    25. }
    26. public Int32_24_16(ReadOnlySpan<byte> bytes)
    27. {
    28. this.V0 = new I24(bytes, 0);
    29. if (bytes.Length > 3) this.V3 = bytes[3];
    30. }
    31. public Int32_24_16(ReadOnlySpan<byte> bytes, int start_idx)
    32. : this(bytes[start_idx..])
    33. {
    34. }
    35. public Int32_24_16(int number)
    36. : this(BitConverter.GetBytes(number))
    37. {
    38. }
    39. public Int32_24_16(long number)
    40. : this(BitConverter.GetBytes(number))
    41. {
    42. }
    43. public Int32_24_16(Int32_24_16 number)
    44. : this(number.AsInteger())
    45. {
    46. }
    47. public int AsInteger() =>
    48. Convert.ToInt32(this.ToString());
    49. public string ToHex()
    50. {
    51. var bytes = this.ToBytes();
    52. var sz = ToSize(bytes);
    53. return Convert.ToHexString(bytes.Take(sz).ToArray()).ToUpper();
    54. }
    55. public override string ToString()
    56. {
    57. if (this.IsZero) return "0";
    58. var bytes = this.ToBytes();
    59. var sz = ToSize(bytes);
    60. var result = BitConverter.ToInt32(bytes);
    61. var bits = 8 * sz;
    62. if (result < (1L << (bits - 1)))
    63. return result.ToString();
    64. return (result - (1L << bits)).ToString();
    65. }
    66. public byte[] ToBytes()
    67. {
    68. var result = new List<byte>();
    69. result.AddRange(this.V0.ToBytes());
    70. result.Add(this.V3);
    71. return [.. result];
    72. }
    73. private static int ToSize(ReadOnlySpan<byte> bytes)
    74. {
    75. var cnt = 0;
    76. var length = bytes.Length;
    77. for (var i = 0; i < length; i++)
    78. if (bytes[^(i + 1)] == 0)
    79. cnt++;
    80. else break;
    81. return length - cnt;
    82. }
    83. #region Equality Operators
    84. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    85. public override bool Equals([NotNullWhen(true)] object? obj)
    86. {
    87. if (obj?.GetType() == typeof(Int32_24_16))
    88. this.Equals((Int32_24_16)obj);
    89. return false;
    90. }
    91. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    92. public override int GetHashCode()
    93. {
    94. return (this.V0.AsInteger() + 4 * this.V3).GetHashCode();
    95. }
    96. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    97. public bool Equals(Int32_24_16 other)
    98. {
    99. return this == other;
    100. }
    101. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    102. public static bool operator ==(Int32_24_16 left, Int32_24_16 right)
    103. {
    104. return left.V0 == right.V0 && left.V3 == right.V3;
    105. }
    106. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    107. public static bool operator !=(Int32_24_16 left, Int32_24_16 right)
    108. {
    109. return !(left == right);
    110. }
    111. #endregion
    112. #region I24
    113. [StructLayout(LayoutKind.Explicit)]
    114. private readonly struct I24
    115. {
    116. [FieldOffset(0)]
    117. private readonly I16 V0;
    118. [FieldOffset(2)]
    119. private readonly byte V2 = 0;
    120. public static I24 Zero => new();
    121. public bool IsZero => this.V0.IsZero && this.V2 == 0;
    122. public I24(string hex)
    123. {
    124. var bytes = Convert.FromHexString(hex);
    125. Array.Reverse(bytes);
    126. this.V0 = new I16(bytes, 0);
    127. if (bytes.Length > 2) this.V2 = bytes[2];
    128. }
    129. public I24(ReadOnlySpan<byte> bytes, int start_idx)
    130. {
    131. this.V0 = new I16(bytes, start_idx);
    132. if (bytes.Length > start_idx + 2) this.V2 = bytes[start_idx + 2];
    133. }
    134. public int AsInteger() =>
    135. Convert.ToInt32(this.ToString());
    136. public override string ToString()
    137. {
    138. if (this.IsZero)
    139. return "0";
    140. var tmp = this.ToBytes();
    141. var sz = ToSize(tmp);
    142. var bytes = new byte[4];
    143. Array.Copy(tmp, bytes, tmp.Length);
    144. var result = BitConverter.ToInt32(bytes);
    145. var bits = 8 * sz;
    146. if (result < (1L << (bits - 1)))
    147. return result.ToString();
    148. return (result - (1L << bits)).ToString();
    149. }
    150. public byte[] ToBytes()
    151. {
    152. var result = new List<byte>();
    153. result.AddRange(this.V0.ToBytes);
    154. result.Add(this.V2);
    155. return [.. result];
    156. }
    157. private static int ToSize(ReadOnlySpan<byte> bytes)
    158. {
    159. var cnt = 0;
    160. var length = bytes.Length;
    161. for (var i = 0; i < length; i++)
    162. if (bytes[^(i + 1)] == 0)
    163. cnt++;
    164. else break;
    165. return length - cnt;
    166. }
    167. #region Equality Operators
    168. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    169. public override bool Equals([NotNullWhen(true)] object? obj)
    170. {
    171. if (obj?.GetType() == typeof(I24))
    172. this.Equals((I24)obj);
    173. return false;
    174. }
    175. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    176. public override int GetHashCode()
    177. {
    178. return (this.V0.AsInteger() + 3 * this.V2).GetHashCode();
    179. }
    180. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    181. public bool Equals(I24 other)
    182. {
    183. return this == other;
    184. }
    185. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    186. public static bool operator ==(I24 left, I24 right)
    187. {
    188. return left.V0 == right.V0 && left.V2 == right.V2;
    189. }
    190. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    191. public static bool operator !=(I24 left, I24 right)
    192. {
    193. return !(left == right);
    194. }
    195. #endregion
    196. }
    197. #endregion I24
    198. #region I16
    199. [StructLayout(LayoutKind.Explicit)]
    200. private readonly struct I16
    201. {
    202. [FieldOffset(0)]
    203. private readonly byte V0 = 0;
    204. [FieldOffset(1)]
    205. private readonly byte V1 = 0;
    206. public static I16 Zero => new();
    207. public bool IsZero => this.V0 == 0 && this.V1 == 0;
    208. public I16(string hex)
    209. {
    210. var bytes = Convert.FromHexString(hex);
    211. Array.Reverse(bytes);
    212. if (bytes.Length > 0) this.V0 = bytes[0];
    213. if (bytes.Length > 1) this.V1 = bytes[1];
    214. }
    215. public I16(ReadOnlySpan<byte> bytes, int start_idx)
    216. {
    217. if (bytes.Length < start_idx + 2)
    218. throw new ArgumentOutOfRangeException(nameof(start_idx));
    219. if (bytes.Length > start_idx + 0) this.V0 = bytes[start_idx + 0];
    220. if (bytes.Length > start_idx + 1) this.V1 = bytes[start_idx + 1];
    221. }
    222. public int AsInteger() =>
    223. Convert.ToInt32(this.ToString());
    224. public override string ToString()
    225. {
    226. if (this.IsZero)
    227. return "0";
    228. var result = (int)this.V0;
    229. result |= this.V1 << 8;
    230. var tsz = Unsafe.SizeOf<I16>();
    231. var bits = 8 * tsz;
    232. if (result < (1L << (bits - 1)))
    233. return result.ToString();
    234. return (result - (1L << bits)).ToString();
    235. }
    236. public byte[] ToBytes => [this.V0, this.V1];
    237. #region Equality Operators
    238. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    239. public override bool Equals([NotNullWhen(true)] object? obj)
    240. {
    241. if (obj?.GetType() == typeof(I16))
    242. this.Equals((I16)obj);
    243. return false;
    244. }
    245. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    246. public override int GetHashCode()
    247. {
    248. return (this.V0 + 2 * this.V1).GetHashCode();
    249. }
    250. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    251. public bool Equals(I16 other)
    252. {
    253. return this == other;
    254. }
    255. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    256. public static bool operator ==(I16 left, I16 right)
    257. {
    258. return left.V0 == right.V0 && left.V1 == right.V1;
    259. }
    260. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    261. public static bool operator !=(I16 left, I16 right)
    262. {
    263. return !(left == right);
    264. }
    265. #endregion
    266. }
    267. #endregion I16
    268. }

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ () aus folgendem Grund: Hab es noch ein bisschen "ausgehübscht"