如何将unsigned long拆分并重新组合成签名短裤?

时间:2016-01-30 04:00:51

标签: c

我需要存储大量数据,但由于旧游戏引擎的限制,我只能使用signed short(我可以根据需要使用尽可能多的这些)。

我需要将unsigned long(0到4,294,967,295)分成多个signed short(-32,768到32,767)。然后我需要将多个signed short重新组合成一个新的unsigned long

例如,取数字4,000,000,000。这应该分成多个signed short,然后重新组合成unsigned long

这可能在C?感谢。

5 个答案:

答案 0 :(得分:2)

除了dbush的答案,您还可以使用union,例如:

Error deserializing ../classifiers/ner-model.ser.gz.
Error snipet is:

Loading classifier from .../classifiers/ner-model.ser.gz ... Error deserializing /home/hrudya/Music/WORKSPACE_SAP/NER/classifiers/ner-model.ser.gz
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.Integer cannot be cast to edu.stanford.nlp.sequences.FeatureFactory
    at edu.stanford.nlp.ie.AbstractSequenceClassifier.loadClassifierNoExceptions(AbstractSequenceClassifier.java:1752)
    at edu.stanford.nlp.ie.AbstractSequenceClassifier.loadClassifierNoExceptions(AbstractSequenceClassifier.java:1703)
    at edu.stanford.nlp.ie.AbstractSequenceClassifier.loadClassifierNoExceptions(AbstractSequenceClassifier.java:1686)
    at edu.stanford.nlp.ie.crf.CRFClassifier.getClassifierNoExceptions(CRFClassifier.java:2825)
    at accs.sap.NER.Test.<clinit>(Test.java:29)
Caused by: java.lang.ClassCastException: java.lang.Integer cannot be cast to edu.stanford.nlp.sequences.FeatureFactory
    at edu.stanford.nlp.ie.crf.CRFClassifier.loadClassifier(CRFClassifier.java:2606)
    at edu.stanford.nlp.ie.AbstractSequenceClassifier.loadClassifier(AbstractSequenceClassifier.java:1622)
    at edu.stanford.nlp.ie.AbstractSequenceClassifier.loadClassifier(AbstractSequenceClassifier.java:1738)
    at edu.stanford.nlp.ie.AbstractSequenceClassifier.loadClassifierNoExceptions(AbstractSequenceClassifier.java:1749)
    ... 4 more

两条短路的数组覆盖单个长值。

答案 1 :(得分:0)

你可以这样做(我使用固定大小类型来正确说明它是如何工作的):

#include<stdio.h>
#include<stdint.h>

int main()
{
    uint32_t val1;
    int16_t val2a, val2b;
    uint32_t val3;

    val1 = 0x11223344;
    printf("val1=%08x\n", val1);

    // to short
    val2a = val1 >> 16;
    val2b = val1 & 0xFFFF;
    printf("val2a=%04x\n", val2a);
    printf("val2b=%04x\n", val2b);

    // to long
    val3 = (uint32_t)val2a << 16;
    val3 |= (uint32_t)val2b;
    printf("val3=%08x\n", val3);

    return 0;
}

输出:

val1=11223344
val2a=1122
val2b=3344
val3=11223344

答案 2 :(得分:0)

这是一种可能的解决方案(假设ulong为32位,sshort为16位):

{{1}}

答案 3 :(得分:0)

有很多方法可以做到这一点。需要考虑的一件事是unsigned long在不同的硬件/操作系统上可能没有相同的大小。您可以使用stdint.h中的确切长度类型来避免歧义(例如uint8_tuint16_t等)。包含确切类型(和cheezy hex值)的一个实现将是:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <limits.h>

int main (void) {

    uint64_t a = 0xfacedeadbeefcafe, b = 0;
    uint16_t s[4] = {0};
    uint32_t i = 0, n = 0;

    printf ("\n a : 0x%16"PRIx64"\n\n", a);

    /* separate uint64_t into 4 uint16_t */
    for (i = 0; i < sizeof a; i += 2, n++)
        printf (" s[%"PRIu32"] : 0x%04"PRIx16"\n", n, 
                (s[n] = (a >> (i * CHAR_BIT))));

    /* combine 4 uint16_t into uint64_t */
    for (n = i = 0; i < sizeof b; i += 2, n++)
        b |= (uint64_t)s[n] << i * CHAR_BIT;

    printf ("\n b : 0x%16"PRIx64"\n\n", b);

    return 0;
}

<强>输出

$ ./bin/uint64_16

 a : 0xfacedeadbeefcafe

 s[0] : 0xcafe
 s[1] : 0xbeef
 s[2] : 0xdead
 s[3] : 0xface

 b : 0xfacedeadbeefcafe

答案 4 :(得分:0)

我认为您的问题是找到存储这些大值的地方。还有一些我们还没有探索过的选项,它们不涉及拆分价值并重新组合它们:

  • 将它们写入文件,稍后再阅读。这可能看起来很愚蠢,但考虑到更大的图景,如果值稍后会在文件中结束,那么这似乎是最有吸引力的选择。
  • 声明您的unsigned long拥有静态存储空白时间,例如在任何代码块之外A.K.A 全局(我讨厌那个术语)或在代码块中使用static关键字。

到目前为止,其他答案都不是严格便携的,而不是看起来对你来说很重要。你似乎在描述一个二进制补码16位signed short表示和一个32位unsigned long表示(你应该放置assert个离子以确保这种情况),它有限制实现选项的含义(即C编译器,操作系统,CPU等)......因此不太可能发生与它们相关的可移植性问题。如果您有点好奇,我还是会讨论这些问题。

相关的可移植性问题是一种类型或另一种类型可能有填充位导致大小不匹配,并且可能存在short的陷阱表示。

更改类型而不是表示更简洁,更容易获得,但不便携;这包括union黑客攻击,您也可以通过将union投射到unsigned long *来避开short *。这些解决方案是最干净的解决方案,尽管不具备移植性,但迄今为止我仍然是Ken Clement's answer的最爱。

二进制转换(>><<运算符)和(&运算符)或(|)运算符在您使用它们时会引入其他可移植性问题签名类型;它们还笨重而且笨拙,导致更多代码进行调试,并且错误发生的可能性更大。

您需要考虑到ULONG_MAX保证至少为4,294,967,295,但{C}标准不保证SHORT_MIN为-32,768;它可能是-32,767(这确实非常罕见,但仍有可能)......可能有一个负零或陷阱表示代替-32,768值。

这意味着您无法轻松地依赖一对signed short能够代表unsigned long的所有值;即使尺寸匹配,您还需要另一位来解释这两个缺失值。

考虑到这一点,你可以使用第三个​​ signed char ......可以通过这种方式避免转换方法的实现定义和未定义的行为。

signed short x = (value      ) & 0xFFF,
             y = (value >> 12) & 0xFFF,
             z = (value >> 24) & 0xFFF;

value =  (unsigned long) x
      + ((unsigned long) y << 12)
      + ((unsigned long) z << 24);