将ulong转换为long

时间:2017-04-20 18:12:24

标签: c++ bit-manipulation endianness

我有一个存储为ulong的号码。我希望存储在内存中的位以2的补码方式解释。所以我希望第一位是符号位等。如果我想转换为long,那么数字被正确解释为2的补码,我该怎么做?

我尝试创建指向同一缓冲区的不同数据类型的指针。然后我将ulong存储到缓冲区中。然后我取消引用一个长指针。然而,这给了我一个糟糕的结果?

我做了:

#include <iostream>
using namespace std;

int main() {
    unsigned char converter_buffer[4];//  

    unsigned long       *pulong;
    long                *plong;


    pulong = (unsigned long*)&converter_buffer;
    plong  =  (long*)&converter_buffer;

    unsigned long ulong_num = 65535; // this has a 1 as the first bit

    *pulong = ulong_num;

    std:: cout << "the number as a long is" << *plong << std::endl;
    return 0;
}

出于某种原因,这给了我相同的正数。   铸造有帮助吗?

3 个答案:

答案 0 :(得分:1)

实际上使用指针是一个好的开始,但你必须首先将<div id="pbc"> <div id="pb"> </div> </div> <div id="test_q"></div> <button id="Result" onclick="renderQuestion()"> <h1 id="result"></h1> </button>转换为unsigned long*,然后你可以将结果转换为void*并取消引用它:

long*

上面的代码将产生以下结果:

#include <iostream>
#include <climits>

int main() {
    unsigned long ulongValue = ULONG_MAX;
    long longValue = *((long*)((void*)&ulongValue));

    std::cout << "ulongValue: " << ulongValue << std::endl;
    std::cout << "longValue:  " << longValue << std::endl;

    return 0;
}

使用模板,您可以在代码中使其更具可读性:

ulongValue: 18446744073709551615
longValue:  -1

请注意,此解决方案绝对不安全,因为您可以向#include <iostream> #include <climits> template<typename T, typename U> T unsafe_cast(const U& from) { return *((T*)((void*)&from)); } int main() { unsigned long ulongValue = ULONG_MAX; long longValue = unsafe_cast<long>(ulongValue); std::cout << "ulongValue: " << ulongValue << std::endl; std::cout << "longValue: " << longValue << std::endl; return 0; } 施放任何内容。这个例子在C中很常见,但我不建议在C ++中使用它。请考虑以下情况:

void*

上面的代码为我提供了以下内容:

#include <iostream>

template<typename T, typename U>
T unsafe_cast(const U& from) {
    return *((T*)((void*)&from));
}

int main() {
    std::cout << std::hex << std::showbase;

    float fValue = 3.14;
    int iValue = unsafe_cast<int>(fValue); // OK, they have same size.

    std::cout << "Hexadecimal representation of " << fValue
              << " is: " << iValue << std::endl;
    std::cout << "Converting back to float results: "
              << unsafe_cast<float>(iValue) << std::endl;

    double dValue = 3.1415926535;
    int lossyValue = unsafe_cast<int>(dValue); // Bad, they have different size.

    std::cout << "Lossy hexadecimal representation of " << dValue
              << " is: " << lossyValue << std::endl;
    std::cout << "Converting back to double results: "
              << unsafe_cast<double>(lossyValue) << std::endl;

    return 0;
}

对于最后一行,你可以获得任何东西,因为转换将从内存中读取垃圾。

修改

lorro所述,使用Hexadecimal representation of 3.14 is: 0x4048f5c3 Converting back to float results: 3.14 Lossy hexadecimal representation of 3.14159 is: 0x54411744 Converting back to double results: 6.98387e-315 更安全,可以防止溢出。所以,这是另一种更安全的类型转换版本:

memcpy()

答案 1 :(得分:0)

你可以这样做:

uint32_t u;
int32_t& s = (int32_t&) u;

然后您可以将su与2的补码互换使用,例如:

s = -1;
std::cout << u << '\n';     // 4294967295

在您的问题中,您询问的是65535,但这是一个正数。你可以这样做:

uint16_t u;
int16_t& s = (int16_t&) u;

u = 65535;
std::cout << s << '\n';    // -1

请注意,将65535(正数)分配给int16_t将是实现定义的行为,它不一定会给-1

原始代码的问题在于,不允许将char缓冲区别名为long。 (而且你可能会溢出你的缓冲区)。但是,可以将整数类型别名为其对应的有符号/无符号类型。

答案 2 :(得分:-1)

通常,如果您有两个大小相同的算术类型,并且想要使用另一个类型重新解释一个类别的位表示,那么可以使用union

#include <stdint.h>

union reinterpret_u64_d_union {
    uint64_t u64;
    double   d;
};

double
reinterpret_u64_as_double(uint64_t v)
{
    union reinterpret_u64_d_union u;
    u.u64 = v;
    return u.d;
}

对于将无符号数转换为具有相同大小的有符号类型(或反之亦然)的特殊情况,您可以使用传统的强制转换:

int64_t
reinterpret_u64_as_i64(uint64_t v)
{
    return (int64_t)v;
}

[u]int64_t并非严格要求强制转换,但如果您没有明确地编写演员表,并且您之间转换的类型很小,则可能涉及“整数促销”,这是通常是不受欢迎的。)

您尝试这样做的方式违反了指针别名规则并引发了未定义的行为。

在C ++中,请注意reinterpret_cast<> 执行union所做的事情;应用于算术类型时,它与static_cast<>相同。

在C ++中,还要注意上面使用union依赖于1999 C 标准中的规则(使用corrigienda) not 最后我检查了正式纳入C ++标准;但是,我熟悉的所有编译器都会按照您的期望进行操作。

最后,在C和C ++中,longunsigned long保证能够代表至少 -2,147,483,647 ... 214,7483,647和0 ... 4,294,967,295。您的测试程序使用了65535,保证可以由longunsigned long表示,因此您可以保持该值不变。好吧,除非你使用了无效的指针别名,编译器决定让恶魔飞出你的鼻子。