将大整数扫描(sscanf)为字节
我需要将大整数扫描(sscanf)为字节,c,scanf,C,Scanf,我需要sscanf一个20位数字,它刚好超出uint64\t的范围。如果我无法在uint64\u t中获得完整的数字,我希望将其作为uint8\u t[10](表示每个字节2位数字),我可以这样做: const char *resp = "+QCCID: 89445003071864431280"; void parse_bytes() { uint8_t bytes[10] = {0}; sscanf(resp, "+QCCID: %2hhu%2hhu%2hhu%2hhu%2hhu%
sscanf
一个20位数字,它刚好超出uint64\t
的范围。如果我无法在uint64\u t
中获得完整的数字,我希望将其作为uint8\u t[10]
(表示每个字节2位数字),我可以这样做:
const char *resp = "+QCCID: 89445003071864431280";
void parse_bytes() {
uint8_t bytes[10] = {0};
sscanf(resp, "+QCCID: %2hhu%2hhu%2hhu%2hhu%2hhu%2hhu%2hhu%2hhu%2hhu%2hhu",
&bytes[9], &bytes[8], &bytes[7], &bytes[6], &bytes[5],
&bytes[4], &bytes[3], &bytes[2], &bytes[1], &bytes[0]);
// print just for testing, not the end result
for(int i=9; i>=0; i--) {
printf("%02d", bytes[i]);
}
}
这很好,但不是特别漂亮的代码。有没有一种更简洁的方法可以将这样的内容扫描到数组中
为了澄清结果的意图:结果不会用于计算,它将通过蓝牙低能量发送到另一个设备
更新:我最终选择了@PetarVelev建议的修改版本。出于本问题范围之外的原因,我使用了位字段结构。如果有人感兴趣,我将我的解决方案作为下面的答案之一发布。根据问题和OP评论判断,您需要更小的占用空间,并且除了打印之外,不会将该数字用于任何操作 那么,为什么不使用相同的技术来获取
uint64\u t
中的前18位和最后两位合一uint8\u t
int main()
{
printf("Hello World");
char arr[21] = "01234567890123456789";
unsigned long long int a;
unsigned char b;
sscanf(arr, "%18llu%2hhu",&a,&b);
printf("%18llu%2hhu",a,b);
return 0;
}
请注意,不会打印前导零
这将减少1个字节的内存占用,显然您不能小于此值,因为它不适合8个字节(uint64_t)。根据问题和OP注释判断,您需要更小的内存占用,并且除了打印之外,不会将数字用于任何操作 那么,为什么不使用相同的技术来获取
uint64\u t
中的前18位和最后两位合一uint8\u t
int main()
{
printf("Hello World");
char arr[21] = "01234567890123456789";
unsigned long long int a;
unsigned char b;
sscanf(arr, "%18llu%2hhu",&a,&b);
printf("%18llu%2hhu",a,b);
return 0;
}
请注意,不会打印前导零
这将减少1个字节的内存占用,显然您不能小于此值,因为它不适合8个字节(uint64_t)。代码可以使用循环和
%n
来跟踪扫描进度
可能不会更漂亮,但允许更简单的M更改
#include <inttypes.h>
#include <stdio.h>
#define M 10
int parse_bytes(const char *resp) {
uint8_t bytes[M] = {0};
int n = 0;
sscanf(resp, "+QCCID: %n", &n);
if (n == 0) return -1; // missing prefix
int m;
for (m = 0; m < M; m++) {
resp += n;
n = 0;
sscanf(resp, "%2" SCNu8 "%n", &bytes[M - 1 - m], &n);
if (n == 0) return -1; // missing number
}
if (resp[n]) return -1; // trailing junk
for (int i = m-1; i >= 0; i--) {
printf("%02d", bytes[i]);
}
return m;
}
未处理的案件。OP断言“20位数字”。如果低于这个数字,我们应该重新思考整个方法。也许可以逐位扫描到d[M*2]
中,然后从“右侧”形成字节[]
,或者:
int n1, n2 = 0;
sscanf(resp, "+QCCID: %n%*[0-9]%n", &n1, &n2);
if (n2 == 0 || n2 - n1 > 2*M) fail();
// now process resp[n2-1] to resp[n1] with TBD code
许多可能性。代码可以使用循环和
%n”
来跟踪扫描进度
可能不会更漂亮,但允许更简单的M更改
#include <inttypes.h>
#include <stdio.h>
#define M 10
int parse_bytes(const char *resp) {
uint8_t bytes[M] = {0};
int n = 0;
sscanf(resp, "+QCCID: %n", &n);
if (n == 0) return -1; // missing prefix
int m;
for (m = 0; m < M; m++) {
resp += n;
n = 0;
sscanf(resp, "%2" SCNu8 "%n", &bytes[M - 1 - m], &n);
if (n == 0) return -1; // missing number
}
if (resp[n]) return -1; // trailing junk
for (int i = m-1; i >= 0; i--) {
printf("%02d", bytes[i]);
}
return m;
}
未处理的案件。OP断言“20位数字”。如果低于这个数字,我们应该重新思考整个方法。也许可以逐位扫描到d[M*2]
中,然后从“右侧”形成字节[]
,或者:
int n1, n2 = 0;
sscanf(resp, "+QCCID: %n%*[0-9]%n", &n1, &n2);
if (n2 == 0 || n2 - n1 > 2*M) fail();
// now process resp[n2-1] to resp[n1] with TBD code
多种可能性。我的最终解决方案如下。我最终得到了一个位域结构,因为我需要在其他地方使用前6位数字。此外,它运行在一个带有
newlib nano
的嵌入式系统上,该系统不支持64位格式,因此我无法扫描/打印uint64\u t
当然,由于不能获取位字段的地址,我首先扫描uint32\t
,然后创建结构
typedef struct __attribute__((packed)) {
uint32_t d1_6 : 20;
uint32_t d7_12 : 20;
uint32_t d13_20 : 32;
} lte_sim_iccid_t;
lte_sim_iccid_t parse_into_struct() {
uint8_t bytes[10] = {0};
uint32_t i1 = 0, i2 = 0, i3 = 0;
sscanf(resp, "+QCCID: %6u%6u%8u", &i1, &i2, &i3);
lte_sim_iccid_t s = { i1, i2, i3 };
// sanity check
printf("ICCID: %u %u %u (size %lu bytes)\n", s.d1_6, s.d7_12, s.d13_20, sizeof(s));
return s;
}
我的最终解决方案如下。我最终得到了一个位域结构,因为我需要在其他地方使用前6位数字。此外,它运行在一个带有
newlib nano
的嵌入式系统上,该系统不支持64位格式,因此我无法扫描/打印uint64\u t
当然,由于不能获取位字段的地址,我首先扫描uint32\t
,然后创建结构
typedef struct __attribute__((packed)) {
uint32_t d1_6 : 20;
uint32_t d7_12 : 20;
uint32_t d13_20 : 32;
} lte_sim_iccid_t;
lte_sim_iccid_t parse_into_struct() {
uint8_t bytes[10] = {0};
uint32_t i1 = 0, i2 = 0, i3 = 0;
sscanf(resp, "+QCCID: %6u%6u%8u", &i1, &i2, &i3);
lte_sim_iccid_t s = { i1, i2, i3 };
// sanity check
printf("ICCID: %u %u %u (size %lu bytes)\n", s.d1_6, s.d7_12, s.d13_20, sizeof(s));
return s;
}
你打算用这个号码做什么?你在计算吗?如果是这样的话,具体是什么?它意味着将BLE转移到不同的设备,因此需要保持尽可能小的内存占用。另一端在用它做什么?如果它只是作为一个ID打印,那么将其作为文本发送就更有意义。当然,它将占用20个字节,但使用更符合格式,因为它不那么麻烦和混乱。一旦到达另一端,它将被保存在数据库中。我同意把它当作一根绳子来处理,这样就不那么麻烦了。这涉及到用户交互,所以我需要看看在BLE上多10个字节会造成多少额外的延迟。你打算用这个数字做什么?你在计算吗?如果是这样的话,具体是什么?它意味着将BLE转移到不同的设备,因此需要保持尽可能小的内存占用。另一端在用它做什么?如果它只是作为一个ID打印,那么将其作为文本发送就更有意义。当然,它将占用20个字节,但使用更符合格式,因为它不那么麻烦和混乱。一旦到达另一端,它将被保存在数据库中。我同意把它当作一根绳子来处理,这样就不那么麻烦了。有用户交互涉及,所以我需要看看有多少额外的延迟造成超过10个字节以上的BLE。我确实认为,但这也为笨拙代码。我现在需要移动两个变量,而不是一个。为了澄清,它不是用来打印的(我只是把它作为一个最低限度的例子)。最终结果将通过蓝牙低能量发送到另一个设备。这只是存储信息。理论上,它可以存储在65位,但这对您没有帮助,因为它是逐字节发送的。所以9是最小值。您可以将信息转换为9个字节,然后将其发送到另一台设备上。考虑创建一个结构:<代码> UTIN 64×T/<代码>和<代码> UIT88T 。假设您的函数需要一个指针,将指针指向Stutt到<代码> uTn8*t*< /Cord>并发送9个字节。我现在需要移动两个变量,而不是一个。为了澄清,它不是用来打印的(我只是把它作为一个最低限度的例子)。最终结果将通过蓝牙低能量发送到另一个设备。这只是存储信息。理论上,它可以被存储