如何将 unsigned char* 转换为 unsigned long long int?

Posted

技术标签:

【中文标题】如何将 unsigned char* 转换为 unsigned long long int?【英文标题】:How to convert unsigned char* to unsigned long long int? 【发布时间】:2021-03-12 13:08:56 【问题描述】:

有谁知道提供执行此逻辑的函数或执行此逻辑的方法的库?

我正在尝试转换:

unsigned char test[] = "\x00\x00\x56\x4b\x7c\x8a\xc5\xde";

到:

94882212005342 / 0x0000564b7c8ac5de

我知道我可以遍历test 中的每个单独字节并利用sprintf 将每个字节转换为字符串并将它们与strcat 连接到缓冲区中,然后通过@ 将缓冲区字符串转换为unsigned long long 987654327@。但是,我正在寻找更全面和简单的东西。有没有这样的方法?

【问题讨论】:

欢迎来到 SO。目前尚不清楚您想要什么。从我的问题中我想你想从字节数组中得到一个 unsigned long long 。但是关于sprintf 的部分根本不适合。 我编辑并提供了更多细节。 你的数组总是正好 9 个字节长吗? 是 8 + 空字节。 为什么你的 64 位内存地址是以字符串开头的?为什么不是无符号长?它已经有所需的字节,大概是正确的顺序,甚至不是一个有效的字符串...... 【参考方案1】:

这只是数学。

unsigned char test[] = "\x00\x00\x56\x4b\x7c\x8a\xc5\xde";
unsigned long long num = 
     (unsigned long long)test[0] << 56 |
     (unsigned long long)test[1] << 48 |
     (unsigned long long)test[2] << 40 |
     (unsigned long long)test[3] << 32 |
     (unsigned long long)test[4] << 24 |
     (unsigned long long)test[5] << 16 |
     (unsigned long long)test[6] <<  8 |
     (unsigned long long)test[7] <<  0;

记得在转换之前强制转换为足够宽的类型。

你有 8 个值:

  0x00, 0x00, 0x56, 0x4b, 0x7c, 0x8a, 0xc5, 0xde 

十进制是:

 0 0 86 75 124 138 197 222

你想拥有:

 94882212005342

这是:

  94882212005342 = 0*2^56 + 0*2^48 + 86*2^40 + 75*2^32 + 124*2^24 + 138*2^16 + 197*2^8 +  222*2^0

这是一个数学运算。你可以写前test[0] * 72057594037927936ull,但它的可读性不如test[0] &lt;&lt; 56

【讨论】:

你能解释一下这里发生了什么吗? test 中取出第一个字节。但它在 56 位输出数。从test 中取出第二个字节。但它在输出编号的 48 位位置。等等 是否可以用循环来压缩它? 见github.com/biiont/gpsd/blob/master/bits.h#L45 @KamilCuk 第 64 行,确定吗? num = getbeu64(test, 0);.【参考方案2】:

我使用 memmove 或 memcpy 函数https://www.tutorialspoint.com/c_standard_library/c_function_memmove.htm做了非常相似的事情

    long long int var = 0; 
    memmove( &var, test, sizeof(var) );

确保使用系统的正确字节顺序。

【讨论】:

这将在 little-endian 系统上失败。 (或大端,我总是混合它们)。 90% 的系统不是小端的吗?有趣的是,它非常优雅。 当然,如果您正在寻找通用解决方案,我完全同意@KamilCuk @KamilCuk,这可能正是 OP 所要求的。 OP 可能已在 OP 的平台上获得了实现定义的 char[] 表示 ull。这个解决方案可能是正确的。 @tstanisl 这违反了严格的别名规则【参考方案3】:

为了记录,您可以这样做:

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

int main(int argc, char *argv[])

    unsigned char test[] = "\x00\x00\x56\x4b\x7c\x8a\xc5\xde";
    uint64_t val=0;
    for(size_t i=0; i<8; i++)
      val |= (uint64_t)test[i] << (7-i)*8;
    printf("%" PRIu64 " %" PRIX64, val, val);

【讨论】:

还有可选的:#include &lt;limits.h&gt; _Static_assert(CHAR_BITS==8, "Get a useful computer instead of that crap.");,以防您需要避开 1980 年代的语言律师、DSP 程序员或其他此类生物。【参考方案4】:

一种有趣但不推荐的方式。如果您想要一个合适的解决方案,请查看KamilCuk's answer

#include <stdio.h>
#include <string.h>

// Reverse an 8-byte array  
void rev(unsigned char *s) 
    unsigned char *end = s + 7; // Evil hard coded value

    while(s<end) 
        unsigned char tmp = *s;
        *s = *end;
        *end = tmp;
        s++;
        end--;
    


int main(void) 
    unsigned char test[] = "\x00\x00\x56\x4b\x7c\x8a\xc5\xde";
    rev(test);                // Reverse the array
    long l;
    memcpy(&l, test, sizeof test);
    printf("%zx\n", l);

请注意,标准并未规定字节顺序。这是在我的机器上工作的。在大多数机器上都是一样的,但是如果对其他架构的可移植性对您很重要。甚至不要考虑这个。

但是,由于您说的值是地址,我建议使用 uintptr_t 而不是 long

【讨论】:

以上是关于如何将 unsigned char* 转换为 unsigned long long int?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 unsigned char* 转换为 unsigned long long int?

将 char* 转换为 unsigned char*

如何使用 Swig 将 unsigned char* 转换为 Python 列表?

将 System::String^ 转换为 unsigned char*

std::string 与 unsigned char[] 和 unsigned char* 有啥不同?

如何从 const char* 转换为 unsigned int c++