如何将大于 255 的值添加到宽整数(编码为 uint_8t 的数组)?
How to add a value greater than 255 to a wide integer (encoded as an array of uint_8t)?
我想向 uint8_t
的数组添加一个值(可能大于 255)。目前,我的实现不允许超过 255,因为 value
是 uint8_t
类型。理想情况下,我希望这个值的类型为 int
.
此代码必须可使用标准库进行编译,并且只能在 C99 中使用。我也无法访问 uint32_t
或 uint_64t
类型。
我如何修改以下代码片段以将 value
从 uint8t
更改为 int ?
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void addArray(uint8_t *dest, size_t sizeDest, uint8_t value){
uint8_t remaining = value;
uint8_t sum;
for (size_t i = 0; i < sizeDest; ++i){
sum = dest[i] + remaining;
if (dest[i] > sum){
remaining -= UINT8_MAX - (dest[i] - sum);
dest[i]=sum;
}
else{
dest[i]=sum;
return;
}
}
}
void printArray(uint8_t *t, size_t arrayLength){
for (int i = 0; i < arrayLength; ++i)
{
printf("%d ", t[i]);
}
printf("\n");
}
int main() {
printf("Max value of uint8_t is %d\n",UINT8_MAX);
int arrayLength = 16;
uint8_t key[] = {
252,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,2
};
uint8_t *testArray = (uint8_t *) malloc(sizeof(uint8_t) * arrayLength);
memcpy(testArray, key, sizeof(uint8_t)*arrayLength);
printf("Before addition\n");
printArray(testArray, arrayLength);
addArray(testArray,arrayLength,15);
printf("After addition\n");
printArray(testArray, arrayLength);
return 0;
}
How to add a value greater than 255 to an array of uint_8t
?
“理想情况下,我想要这个 int 类型的值。” --> 由于目标是“大于 255 的值”,我们可以简化并使用 unsigned
.
将 unsigned
添加到数组中索引的 uint8_t
。由于可能会发生溢出,请使用比 unsigned
math.
更宽的范围
// Return overflow amount
// void addArray(uint8_t *dest, size_t sizeDest, uint8_t value){
unsigned addArray(uint8_t *dest, size_t sizeDest, unsigned value){
unsigned long long sum = value; // Use some type wider than unsigned
for (size_t i = 0; i < sizeDest; ++i) {
sum += dest[i];
dest[i] = (uint8_t) sum; // Save 8 lower bits
sum >>= 8; // Continue with the upper bits
}
return (unsigned) sum;
}
...或更像 OP 的代码,没有使用更宽的整数数学运算。
unsigned addArray(uint8_t *dest, size_t sizeDest, unsigned value){
#define UINT_MAX_PLUS1_DIV256 ((UINT_MAX - UINT_MAX/2) >> 7)
unsigned remaining = value;
for (size_t i = 0; i < sizeDest; ++i) {
unsigned sum = remaining + dest[i];
dest[i] = sum; // Save lower bits
if (sum < remaining) { // Overflow occurred in remaining + dest[i]
remaining = sum >> 8;
remaining += UINT_MAX_PLUS1_DIV256 // add back overflow bit / 256
} else{
remaining = sum >> 8; // Continue with the upper bits
}
}
return remaining
}
你说你不能使用uint32_t
或uint64_t
,但你可以使用int
。如果是这样,这很简单。只需使用 int
传递您的新值 和 来跟踪部分,运行 总和。
我是这样做的;它与@chux 发布的代码非常相似。我还简化了逻辑:您实际上不需要保留单独的 sum
和 remaining
值,所以我将其归结为一个变量,我称之为 carry
,输入 int
.
void addArray(uint8_t *dest, size_t sizeDest, int value){
int carry = value;
for (size_t i = 0; i < sizeDest; ++i){
carry = dest[i] + carry;
dest[i] = carry & 0xff;
carry >>= 8;
}
}
在每次循环中,carry
要么是我们要添加的值,要么是前一个“数字”剩余的进位。我们将进位添加到当前数字,尽可能多地存储它 - 低位 8 位 - 回到当前数字,并保留剩余的(即,在使用 >>=
丢弃低位之后-order 8 位,它们是我们刚刚存储在 carry
变量中的 dest[i]
) 以备下次使用。
为什么这行得通?好吧,这与您手动添加一列数字时所做的相同,使用的是我们在小学时都学过的技术。假设您要添加
6
14
7
23
13
+ 4
----
将 1 的列加起来后,您得到 27,然后您说:“好吧,那是 7,进 2”。 (你 而不是 说,“携带 20”。)你的部分和是 27,它的“下半部分”(7,或 27 % 10)是最后和的一个位置,“上半部分”(2,或 27 / 10)是进入十列的进位。
因此,如果您不熟悉或不习惯那些“按位”运算符,您可以使用 %
和 /
执行等效操作,除了使用 256 的因数而不是 10:
void addArray(uint8_t *dest, size_t sizeDest, int value){
int carry = value;
for (size_t i = 0; i < sizeDest; ++i){
carry = dest[i] + carry;
dest[i] = carry % 256;
carry /= 256;
}
}
基本上你在这里以 256 为基数执行加法。
根据您的需要和限制,对 value
和 carry
使用类型 int16_t
、unsigned int
或 uint16_t
可能会有一些价值, 而不是普通的 int
.
我通过调用
测试了这个
addArray(testArray,arrayLength,300);
它打印了
Before addition
252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 2
After addition
40 1 0 0 0 0 0 0 0 0 0 0 0 0 0 3
看起来不错。作为第二个测试,
addArray(testArray,arrayLength,123456789);
打印
After addition
17 205 91 7 0 0 0 0 0 0 0 0 0 0 0 3
(在下面的“附录”中有更多关于这些测试的信息。)
正如@chux 在评论中指出的那样,这段代码确实有其局限性。如果您尝试添加的值接近 int
可以容纳的最大值,则 carry
变量可能会溢出(即,在 carry = dest[i] + carry
行)。但只要 value
小于或等于 INT_MAX - 255
(并且大于或等于零!),你应该没问题。
当然,如果您尝试添加的值可能很大,它也可能大于单个 int
可以容纳的值,在这种情况下,您需要将它传递给一些换句话说,可能是 uint8_t
的第二个数组,就像 dest
一样——然后你会发现自己正在编写一个完全通用的多精度加法器。
附录:为了仔细检查这些结果,并演示实际发生的情况,我们可以在 dc
,即 Unix/Linux 任意精度计算器中执行相同的算法。我已经确定@Tifa 的初始 key
值为 3987683987354747618711421180841033724。我们将使用 dc
以各种基数打印出该数字,并向其添加 15、300 和 123456789。
$ dc
3987683987354747618711421180841033724 # original key
p # print it
3987683987354747618711421180841033724
16o p # set output base to 16 and print
2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFC
256o p # set output base to 256 and print
002 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252
15 + p # add 15 and print (still base 256)
003 000 000 000 000 000 000 000 000 000 000 000 000 000 000 011
3987683987354747618711421180841033724 # original key again
300 + p # add 300 and print
003 000 000 000 000 000 000 000 000 000 000 000 000 000 001 040
3987683987354747618711421180841033724 # original key again
123456789 + p # add and print
003 000 000 000 000 000 000 000 000 000 000 000 007 091 205 017
dc 的 base-256 格式对应于 Tifa 的 printArray
函数的输出,尽管是更传统的从左到右的顺序。
我想向 uint8_t
的数组添加一个值(可能大于 255)。目前,我的实现不允许超过 255,因为 value
是 uint8_t
类型。理想情况下,我希望这个值的类型为 int
.
此代码必须可使用标准库进行编译,并且只能在 C99 中使用。我也无法访问 uint32_t
或 uint_64t
类型。
我如何修改以下代码片段以将 value
从 uint8t
更改为 int ?
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void addArray(uint8_t *dest, size_t sizeDest, uint8_t value){
uint8_t remaining = value;
uint8_t sum;
for (size_t i = 0; i < sizeDest; ++i){
sum = dest[i] + remaining;
if (dest[i] > sum){
remaining -= UINT8_MAX - (dest[i] - sum);
dest[i]=sum;
}
else{
dest[i]=sum;
return;
}
}
}
void printArray(uint8_t *t, size_t arrayLength){
for (int i = 0; i < arrayLength; ++i)
{
printf("%d ", t[i]);
}
printf("\n");
}
int main() {
printf("Max value of uint8_t is %d\n",UINT8_MAX);
int arrayLength = 16;
uint8_t key[] = {
252,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,2
};
uint8_t *testArray = (uint8_t *) malloc(sizeof(uint8_t) * arrayLength);
memcpy(testArray, key, sizeof(uint8_t)*arrayLength);
printf("Before addition\n");
printArray(testArray, arrayLength);
addArray(testArray,arrayLength,15);
printf("After addition\n");
printArray(testArray, arrayLength);
return 0;
}
How to add a value greater than 255 to an array of
uint_8t
?
“理想情况下,我想要这个 int 类型的值。” --> 由于目标是“大于 255 的值”,我们可以简化并使用 unsigned
.
将 unsigned
添加到数组中索引的 uint8_t
。由于可能会发生溢出,请使用比 unsigned
math.
// Return overflow amount
// void addArray(uint8_t *dest, size_t sizeDest, uint8_t value){
unsigned addArray(uint8_t *dest, size_t sizeDest, unsigned value){
unsigned long long sum = value; // Use some type wider than unsigned
for (size_t i = 0; i < sizeDest; ++i) {
sum += dest[i];
dest[i] = (uint8_t) sum; // Save 8 lower bits
sum >>= 8; // Continue with the upper bits
}
return (unsigned) sum;
}
...或更像 OP 的代码,没有使用更宽的整数数学运算。
unsigned addArray(uint8_t *dest, size_t sizeDest, unsigned value){
#define UINT_MAX_PLUS1_DIV256 ((UINT_MAX - UINT_MAX/2) >> 7)
unsigned remaining = value;
for (size_t i = 0; i < sizeDest; ++i) {
unsigned sum = remaining + dest[i];
dest[i] = sum; // Save lower bits
if (sum < remaining) { // Overflow occurred in remaining + dest[i]
remaining = sum >> 8;
remaining += UINT_MAX_PLUS1_DIV256 // add back overflow bit / 256
} else{
remaining = sum >> 8; // Continue with the upper bits
}
}
return remaining
}
你说你不能使用uint32_t
或uint64_t
,但你可以使用int
。如果是这样,这很简单。只需使用 int
传递您的新值 和 来跟踪部分,运行 总和。
我是这样做的;它与@chux 发布的代码非常相似。我还简化了逻辑:您实际上不需要保留单独的 sum
和 remaining
值,所以我将其归结为一个变量,我称之为 carry
,输入 int
.
void addArray(uint8_t *dest, size_t sizeDest, int value){
int carry = value;
for (size_t i = 0; i < sizeDest; ++i){
carry = dest[i] + carry;
dest[i] = carry & 0xff;
carry >>= 8;
}
}
在每次循环中,carry
要么是我们要添加的值,要么是前一个“数字”剩余的进位。我们将进位添加到当前数字,尽可能多地存储它 - 低位 8 位 - 回到当前数字,并保留剩余的(即,在使用 >>=
丢弃低位之后-order 8 位,它们是我们刚刚存储在 carry
变量中的 dest[i]
) 以备下次使用。
为什么这行得通?好吧,这与您手动添加一列数字时所做的相同,使用的是我们在小学时都学过的技术。假设您要添加
6
14
7
23
13
+ 4
----
将 1 的列加起来后,您得到 27,然后您说:“好吧,那是 7,进 2”。 (你 而不是 说,“携带 20”。)你的部分和是 27,它的“下半部分”(7,或 27 % 10)是最后和的一个位置,“上半部分”(2,或 27 / 10)是进入十列的进位。
因此,如果您不熟悉或不习惯那些“按位”运算符,您可以使用 %
和 /
执行等效操作,除了使用 256 的因数而不是 10:
void addArray(uint8_t *dest, size_t sizeDest, int value){
int carry = value;
for (size_t i = 0; i < sizeDest; ++i){
carry = dest[i] + carry;
dest[i] = carry % 256;
carry /= 256;
}
}
基本上你在这里以 256 为基数执行加法。
根据您的需要和限制,对 value
和 carry
使用类型 int16_t
、unsigned int
或 uint16_t
可能会有一些价值, 而不是普通的 int
.
我通过调用
测试了这个addArray(testArray,arrayLength,300);
它打印了
Before addition
252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 2
After addition
40 1 0 0 0 0 0 0 0 0 0 0 0 0 0 3
看起来不错。作为第二个测试,
addArray(testArray,arrayLength,123456789);
打印
After addition
17 205 91 7 0 0 0 0 0 0 0 0 0 0 0 3
(在下面的“附录”中有更多关于这些测试的信息。)
正如@chux 在评论中指出的那样,这段代码确实有其局限性。如果您尝试添加的值接近 int
可以容纳的最大值,则 carry
变量可能会溢出(即,在 carry = dest[i] + carry
行)。但只要 value
小于或等于 INT_MAX - 255
(并且大于或等于零!),你应该没问题。
当然,如果您尝试添加的值可能很大,它也可能大于单个 int
可以容纳的值,在这种情况下,您需要将它传递给一些换句话说,可能是 uint8_t
的第二个数组,就像 dest
一样——然后你会发现自己正在编写一个完全通用的多精度加法器。
附录:为了仔细检查这些结果,并演示实际发生的情况,我们可以在 dc
,即 Unix/Linux 任意精度计算器中执行相同的算法。我已经确定@Tifa 的初始 key
值为 3987683987354747618711421180841033724。我们将使用 dc
以各种基数打印出该数字,并向其添加 15、300 和 123456789。
$ dc
3987683987354747618711421180841033724 # original key
p # print it
3987683987354747618711421180841033724
16o p # set output base to 16 and print
2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFC
256o p # set output base to 256 and print
002 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252
15 + p # add 15 and print (still base 256)
003 000 000 000 000 000 000 000 000 000 000 000 000 000 000 011
3987683987354747618711421180841033724 # original key again
300 + p # add 300 and print
003 000 000 000 000 000 000 000 000 000 000 000 000 000 001 040
3987683987354747618711421180841033724 # original key again
123456789 + p # add and print
003 000 000 000 000 000 000 000 000 000 000 000 007 091 205 017
dc 的 base-256 格式对应于 Tifa 的 printArray
函数的输出,尽管是更传统的从左到右的顺序。