从命令行获取 128 位整数
Getting a 128 bits integer from command line
我正在尝试使用 unsigned long long
密钥来执行 Tiny Encryption Algorithm 算法。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv){
unsigned int key[4] = { 0 };
*key = strtoll(argv[1], NULL, 10);
printf("%s key = %llu\n", argv[0], key);
return 0;
}
这是我的输入:
./a.out 9223372036854775700
这是输出:
./a.out key = 140723741574976
所以我在 argv[1]
中传递了一个 128 位密钥。它不应该在内存中正确地转换为 unsigned int
数组吗?
所以,我想弄清楚为什么这是我的程序的输出。这与字节顺序有关吗?
long long
仅指定至少包含 64 位。您最好将密钥作为十六进制传递并手动将其解析为字节数组
为什么不手动做呢?获取一个 __int128
类型变量,遍历输入的每个数字并将其插入变量中:
int main(int argc, char** argv){
__int128 key = 0;
int i;
for (i=0; i<strlen(argv[1]); i++){
key *= 10; // "shift" current value to make space for adding one more decimal
key += argv[1][i] - '0'; // convert ascii character to number
}
printf("%s key = %llu\n", argv[0], key);
return 0;
}
请注意,如果 argv[1]
太长,密钥将丢弃其第一位而不是最后一位。所以,根据您的喜好,也许这也是您需要注意的事情
代码试图打印数组 key[0]
的地址而不是它的值。这不是字节序问题。启用所有编译器警告以节省时间。
*key = strtoll(argv[1], NULL, 10);
尝试将 long long
(至少 64 位)保存到 unsigned int
,这可能只有 32。
字符串“9223372036854775700”代表一个63位数。
首先尝试使用至少 64 位数字的 unsigned long long
。
int main(int argc, char** argv){
// unsigned int key[4] = { 0 };
unsigned long long key = strtoull(argv[1], NULL, 10);
printf("%s key = %llu\n", argv[0], key);
return 0;
}
C 没有指定支持 128 位整数。可以编写用户代码来应对这种情况。 使用十六进制文本的想法很好。
因为 int
可以有多种尺寸,所以更好用
#include <stdint.h>
// unsigned int key[4];
uint32_t key[4];
示例代码想法
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
uint16_t u[8];
} my_uint128_t;
my_uint128_t strtomy_uint128(const char *s, char **endptr, int base) {
my_uint128_t y = {0};
while (isalnum((unsigned char ) *s)) {
char *endptr;
uint32_t sum = (uint32_t) strtoul((char[2]) {*s, '[=12=]'}, &endptr, base);
if (*endptr) {
break;
}
for (int i = 0; i < 8; i++) {
sum += y.u[i] * (uint32_t) base;
y.u[i] = (uint16_t) sum;
sum >>= 16;
}
if (sum) {
errno = ERANGE;
for (int i = 0; i < 8; i++) {
y.u[i] = UINT16_MAX;
}
}
s++;
}
if (endptr) {
*endptr = (char *) s;
}
return y;
}
void uint128_dump(my_uint128_t x) {
for (int i = 8; i > 0; ) {
i--;
printf("%04" PRIX16 "%c", x.u[i], i ? ' ' : '\n');
}
}
int main(void) {
my_uint128_t a = strtomy_uint128("9223372036854775700", 0, 10);
uint128_dump(a);
}
输出
0000 0000 0000 0000 7FFF FFFF FFFF FF94
退后一步,看看您要实现的目标。微型加密算法不适用于 128 位整数,但适用于 128 位密钥;密钥由四个 32 位无符号整数组成。
您真正需要的是一种将十进制(或十六进制或其他一些基数)128 位无符号整数从字符串解析为四个 32 位无符号整数元素的方法。
我建议写一个乘加函数,它取 quad-32 位值,将它乘以一个 32 位常量,然后加上另一个 32 位常量:
#include <stdint.h>
uint32_t muladd128(uint32_t quad[4], const uint32_t mul, const uint32_t add)
{
uint64_t temp = 0;
temp = (uint64_t)quad[3] * (uint64_t)mul + add;
quad[3] = temp;
temp = (uint64_t)quad[2] * (uint64_t)mul + (temp >> 32);
quad[2] = temp;
temp = (uint64_t)quad[1] * (uint64_t)mul + (temp >> 32);
quad[1] = temp;
temp = (uint64_t)quad[0] * (uint64_t)mul + (temp >> 32);
quad[0] = temp;
return temp >> 32;
}
以上使用最重要的第一个词序。如果结果溢出,它 returns 非零;事实上,它 returns 32 位溢出本身。
这样,就可以很容易地解析描述二进制、八进制、十进制或十六进制非负 128 位整数的字符串:
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
static void clear128(uint32_t quad[4])
{
quad[0] = quad[1] = quad[2] = quad[3] = 0;
}
/* muladd128() */
static const char *parse128(uint32_t quad[4], const char *from)
{
if (!from) {
errno = EINVAL;
return NULL;
}
while (*from == '\t' || *from == '\n' || *from == '\v' ||
*from == '\f' || *from == '\r' || *from == ' ')
from++;
if (from[0] == '0' && (from[1] == 'x' || from[1] == 'X') &&
((from[2] >= '0' && from[2] <= '9') ||
(from[2] >= 'A' && from[2] <= 'F') ||
(from[2] >= 'a' && from[2] <= 'f'))) {
/* Hexadecimal */
from += 2;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '9') {
if (muladd128(quad, 16, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
if (*from >= 'A' && *from <= 'F') {
if (muladd128(quad, 16, *from - 'A' + 10)) {
errno = ERANGE;
return NULL;
}
from++;
} else
if (*from >= 'a' && *from <= 'f') {
if (muladd128(quad, 16, *from - 'a' + 10)) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] == '0' && (from[1] == 'b' || from[1] == 'B') &&
(from[2] >= '0' && from[2] <= '1')) {
/* Binary */
from += 2;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '1') {
if (muladd128(quad, 2, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] == '0' &&
(from[1] >= '0' && from[1] <= '7')) {
/* Octal */
from += 1;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '7') {
if (muladd128(quad, 8, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] >= '0' && from[0] <= '9') {
/* Decimal */
clear128(quad);
while (1)
if (*from >= '0' && *from <= '9') {
if (muladd128(quad, 10, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
/* Not a recognized number. */
errno = EINVAL;
return NULL;
}
int main(int argc, char *argv[])
{
uint32_t key[4];
int arg;
for (arg = 1; arg < argc; arg++) {
const char *end = parse128(key, argv[arg]);
if (end) {
if (*end != '[=11=]')
printf("%s: 0x%08x%08x%08x%08x (+ \"%s\")\n", argv[arg], key[0], key[1], key[2], key[3], end);
else
printf("%s: 0x%08x%08x%08x%08x\n", argv[arg], key[0], key[1], key[2], key[3]);
fflush(stdout);
} else {
switch (errno) {
case ERANGE:
fprintf(stderr, "%s: Too large.\n", argv[arg]);
break;
case EINVAL:
fprintf(stderr, "%s: Not a nonnegative integer in binary, octal, decimal, or hexadecimal notation.\n", argv[arg]);
break;
default:
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
break;
}
}
}
return EXIT_SUCCESS;
}
添加对有时会用到的Base64和Base85的支持非常简单;或者对于任何小于 232.
的基数
而且,如果您考虑以上内容,这完全取决于您需要什么。
我正在尝试使用 unsigned long long
密钥来执行 Tiny Encryption Algorithm 算法。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv){
unsigned int key[4] = { 0 };
*key = strtoll(argv[1], NULL, 10);
printf("%s key = %llu\n", argv[0], key);
return 0;
}
这是我的输入:
./a.out 9223372036854775700
这是输出:
./a.out key = 140723741574976
所以我在 argv[1]
中传递了一个 128 位密钥。它不应该在内存中正确地转换为 unsigned int
数组吗?
所以,我想弄清楚为什么这是我的程序的输出。这与字节顺序有关吗?
long long
仅指定至少包含 64 位。您最好将密钥作为十六进制传递并手动将其解析为字节数组
为什么不手动做呢?获取一个 __int128
类型变量,遍历输入的每个数字并将其插入变量中:
int main(int argc, char** argv){
__int128 key = 0;
int i;
for (i=0; i<strlen(argv[1]); i++){
key *= 10; // "shift" current value to make space for adding one more decimal
key += argv[1][i] - '0'; // convert ascii character to number
}
printf("%s key = %llu\n", argv[0], key);
return 0;
}
请注意,如果 argv[1]
太长,密钥将丢弃其第一位而不是最后一位。所以,根据您的喜好,也许这也是您需要注意的事情
代码试图打印数组 key[0]
的地址而不是它的值。这不是字节序问题。启用所有编译器警告以节省时间。
*key = strtoll(argv[1], NULL, 10);
尝试将 long long
(至少 64 位)保存到 unsigned int
,这可能只有 32。
字符串“9223372036854775700”代表一个63位数。
首先尝试使用至少 64 位数字的 unsigned long long
。
int main(int argc, char** argv){
// unsigned int key[4] = { 0 };
unsigned long long key = strtoull(argv[1], NULL, 10);
printf("%s key = %llu\n", argv[0], key);
return 0;
}
C 没有指定支持 128 位整数。可以编写用户代码来应对这种情况。
因为 int
可以有多种尺寸,所以更好用
#include <stdint.h>
// unsigned int key[4];
uint32_t key[4];
示例代码想法
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
uint16_t u[8];
} my_uint128_t;
my_uint128_t strtomy_uint128(const char *s, char **endptr, int base) {
my_uint128_t y = {0};
while (isalnum((unsigned char ) *s)) {
char *endptr;
uint32_t sum = (uint32_t) strtoul((char[2]) {*s, '[=12=]'}, &endptr, base);
if (*endptr) {
break;
}
for (int i = 0; i < 8; i++) {
sum += y.u[i] * (uint32_t) base;
y.u[i] = (uint16_t) sum;
sum >>= 16;
}
if (sum) {
errno = ERANGE;
for (int i = 0; i < 8; i++) {
y.u[i] = UINT16_MAX;
}
}
s++;
}
if (endptr) {
*endptr = (char *) s;
}
return y;
}
void uint128_dump(my_uint128_t x) {
for (int i = 8; i > 0; ) {
i--;
printf("%04" PRIX16 "%c", x.u[i], i ? ' ' : '\n');
}
}
int main(void) {
my_uint128_t a = strtomy_uint128("9223372036854775700", 0, 10);
uint128_dump(a);
}
输出
0000 0000 0000 0000 7FFF FFFF FFFF FF94
退后一步,看看您要实现的目标。微型加密算法不适用于 128 位整数,但适用于 128 位密钥;密钥由四个 32 位无符号整数组成。
您真正需要的是一种将十进制(或十六进制或其他一些基数)128 位无符号整数从字符串解析为四个 32 位无符号整数元素的方法。
我建议写一个乘加函数,它取 quad-32 位值,将它乘以一个 32 位常量,然后加上另一个 32 位常量:
#include <stdint.h>
uint32_t muladd128(uint32_t quad[4], const uint32_t mul, const uint32_t add)
{
uint64_t temp = 0;
temp = (uint64_t)quad[3] * (uint64_t)mul + add;
quad[3] = temp;
temp = (uint64_t)quad[2] * (uint64_t)mul + (temp >> 32);
quad[2] = temp;
temp = (uint64_t)quad[1] * (uint64_t)mul + (temp >> 32);
quad[1] = temp;
temp = (uint64_t)quad[0] * (uint64_t)mul + (temp >> 32);
quad[0] = temp;
return temp >> 32;
}
以上使用最重要的第一个词序。如果结果溢出,它 returns 非零;事实上,它 returns 32 位溢出本身。
这样,就可以很容易地解析描述二进制、八进制、十进制或十六进制非负 128 位整数的字符串:
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
static void clear128(uint32_t quad[4])
{
quad[0] = quad[1] = quad[2] = quad[3] = 0;
}
/* muladd128() */
static const char *parse128(uint32_t quad[4], const char *from)
{
if (!from) {
errno = EINVAL;
return NULL;
}
while (*from == '\t' || *from == '\n' || *from == '\v' ||
*from == '\f' || *from == '\r' || *from == ' ')
from++;
if (from[0] == '0' && (from[1] == 'x' || from[1] == 'X') &&
((from[2] >= '0' && from[2] <= '9') ||
(from[2] >= 'A' && from[2] <= 'F') ||
(from[2] >= 'a' && from[2] <= 'f'))) {
/* Hexadecimal */
from += 2;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '9') {
if (muladd128(quad, 16, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
if (*from >= 'A' && *from <= 'F') {
if (muladd128(quad, 16, *from - 'A' + 10)) {
errno = ERANGE;
return NULL;
}
from++;
} else
if (*from >= 'a' && *from <= 'f') {
if (muladd128(quad, 16, *from - 'a' + 10)) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] == '0' && (from[1] == 'b' || from[1] == 'B') &&
(from[2] >= '0' && from[2] <= '1')) {
/* Binary */
from += 2;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '1') {
if (muladd128(quad, 2, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] == '0' &&
(from[1] >= '0' && from[1] <= '7')) {
/* Octal */
from += 1;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '7') {
if (muladd128(quad, 8, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] >= '0' && from[0] <= '9') {
/* Decimal */
clear128(quad);
while (1)
if (*from >= '0' && *from <= '9') {
if (muladd128(quad, 10, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
/* Not a recognized number. */
errno = EINVAL;
return NULL;
}
int main(int argc, char *argv[])
{
uint32_t key[4];
int arg;
for (arg = 1; arg < argc; arg++) {
const char *end = parse128(key, argv[arg]);
if (end) {
if (*end != '[=11=]')
printf("%s: 0x%08x%08x%08x%08x (+ \"%s\")\n", argv[arg], key[0], key[1], key[2], key[3], end);
else
printf("%s: 0x%08x%08x%08x%08x\n", argv[arg], key[0], key[1], key[2], key[3]);
fflush(stdout);
} else {
switch (errno) {
case ERANGE:
fprintf(stderr, "%s: Too large.\n", argv[arg]);
break;
case EINVAL:
fprintf(stderr, "%s: Not a nonnegative integer in binary, octal, decimal, or hexadecimal notation.\n", argv[arg]);
break;
default:
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
break;
}
}
}
return EXIT_SUCCESS;
}
添加对有时会用到的Base64和Base85的支持非常简单;或者对于任何小于 232.
的基数而且,如果您考虑以上内容,这完全取决于您需要什么。