我在无符号整数(uint32_t)中有许多位数(位数可以更改)。例如(示例中为12位):
uint32_t a = 0xF9C;
这些位表示该长度的有符号整数。 在这种情况下,十进制数应为-100。 我想将变量存储在带符号的变量中,并且获取的是实际值。 如果我只是使用:
int32_t b = (int32_t)a;
它只是值3996,因为它被强制转换为(0x00000F9C),但实际上必须为(0xFFFFFF9C)
我知道一种方法:
union test
{
signed temp :12;
};
union test x;
x.temp = a;
int32_t result = (int32_t) x.temp;
现在我得到正确的值-100
但是有更好的方法吗? 我的解决方案不是很灵活,因为我提到位数可以变化(1-64位之间的任意值)。
答案 0 :(得分:3)
但是有更好的方法吗?
嗯,取决于您所说的“更好”是什么意思。下面的示例显示了一种更灵活的方法,因为位字段的大小不固定。如果您的用例需要不同的位大小,则可以考虑采用“更好”的方式。
unsigned sign_extend(unsigned x, unsigned num_bits)
{
unsigned f = ~((1 << (num_bits-1)) - 1);
if (x & f) x = x | f;
return x;
}
int main(void)
{
int x = sign_extend(0xf9c, 12);
printf("%d\n", x);
int y = sign_extend(0x79c, 12);
printf("%d\n", y);
}
输出:
-100
1948
答案 1 :(得分:1)
无分支签名的扩展位域的方法(Henry S. Warren Jr.,CACM v20 n6 1977年6月)是这样的:
View
@model WebApplication2.Models.UploadFiles
@{
ViewBag.Title = "Paygroup Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Update Paygroup</h2>
@using (Html.BeginForm("Edit", "UpdateFiles", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
<div class="form-group">
@Html.LabelFor(m => m.PayGroup, new { @class = "control-label" })
@Html.EditorFor(m => m.PayGroup, new { htmlAttributes = new { @class = "form-control", placeholder = Html.DisplayNameFor(m => m.PayGroup) } })
@Html.ValidationMessageFor(m => m.PayGroup, "", new { @class = "text-danger" })
<input type="submit" value="Add" class="btn btn-default" />
<input type="submit" value="Delete" class="btn btn-default" />
</div>
}
<table class="table table-striped">
<tr>
<th>Paygroups</th>
<th>Date added</th>
</tr>
@foreach (var pg in Model.Paygroups)
{
<tr>
<td>@pg</td>
</tr>
}
@foreach (var date in Model.DateAdded)
{
<tr>
<td>@date</td>
</tr>
}
</table>
根据@Lundin的评论进行更新
这是经过测试的代码(打印-100):
public class UpdateFilesController : Controller
{
// GET: Default
public ActionResult Edit()
{
var fullpath = Path.Combine(Server.MapPath("~/sourcefiles"), "paygroup.txt");
List<string> paygroupsList = new List<string>();
List<string> DateList = new List<string>();
string line;
using (var sr = new StreamReader(fullpath))
{
while ((line = sr.ReadLine()) != null)
{
string[] strArray = line.Split('|');
paygroupsList.Add(strArray[0]);
DateList.Add(strArray[1]);
}
UploadFiles model = new UploadFiles()
{
Paygroups = paygroupsList,
DateAdded = DateList
};
return View(model);
}
}
答案 2 :(得分:0)
当右移带符号负整数时,这取决于符号扩展的实现定义行为。首先,将无符号整数一直向左移动,直到符号位变为MSB,然后将其强制转换为有符号整数,然后移回:
#include <stdio.h>
#include <stdint.h>
#define NUMBER_OF_BITS 12
int main(void) {
uint32_t x = 0xF9C;
int32_t y = (int32_t)(x << (32-NUMBER_OF_BITS)) >> (32-NUMBER_OF_BITS);
printf("%d\n", y);
return 0;
}
答案 3 :(得分:0)
这是您的问题的 a 解决方案:
int32_t sign_extend(uint32_t x, uint32_t bit_size)
{
// The expression (0xffffffff << bit_size) will fill the upper bits to sign extend the number.
// The expression (-(x >> (bit_size-1))) is a mask that will zero the previous expression in case the number was positive (to avoid having an if statemet).
return (0xffffffff << bit_size) & (-(x >> (bit_size-1))) | x;
}
int main()
{
printf("%d\n", sign_extend(0xf9c, 12)); // -100
printf("%d\n", sign_extend(0x7ff, 12)); // 2047
return 0;
}
答案 4 :(得分:-1)
执行此操作的理智,可移植且有效的方法只是掩盖数据部分,然后用0xFF ...填充其他所有内容以获取正确的2的补码表示形式。您需要知道多少位是数据部分。
(1u << data_length) - 1
屏蔽数据。 data_length = 8
,数据掩码变为0xFF
。让我们称之为data_mask
。a & data_mask
。~data_mask
即可实现。a = (a & data_mask) | ~data_mask
。现在a
是正确的32位2的补码。示例:
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
const uint32_t data_length = 8;
const uint32_t data_mask = (1u << data_length) - 1;
uint32_t a = 0xF9C;
a = (a & data_mask) | ~data_mask;
printf("%"PRIX32 "\t%"PRIi32, a, (int32_t)a);
}
输出:
FFFFFF9C -100
这取决于int
是32位2的补码,但可以完全移植。