我有一个存储为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;
}
出于某种原因,这给了我相同的正数。 铸造有帮助吗?
答案 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;
然后您可以将s
和u
与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 ++中,long
和unsigned long
保证能够代表至少 -2,147,483,647 ... 214,7483,647和0 ... 4,294,967,295。您的测试程序使用了65535,保证可以由long
和unsigned long
表示,因此您可以保持该值不变。好吧,除非你使用了无效的指针别名,编译器决定让恶魔飞出你的鼻子。