我需要sscanf
一个20位数字,该数字刚刚超出uint64_t
的范围。如果无法在uint64_t
中包含完整的数字,我希望将其作为uint8_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]);
}
}
这很好用,但不是特别漂亮的代码。有没有更简洁的方法可以将类似的内容扫描到数组中?
要弄清楚结果的意图:该结果将不会用于计算,它将通过Bluetooth Low Energy发送到另一台设备。
更新:我最终得到了@PetarVelev建议的修改版本。由于这个问题范围之外的原因,我使用了位域结构。如果有人感兴趣,我将解决方案作为下面的答案之一。
答案 0 :(得分:3)
代码可以使用循环和"%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;
}
如果代码要确保连续的数字并且没有空格或符号字符,可以添加测试:
n = 0;
if (!isdigit((unsigned char) *resp)) return -1; // digit expected.
sscanf(resp, "%2" SCNu8 "%n", &bytes[M - 1 - m], &n);
未处理的案件。 OP断言“ 20位数字”。如果少于这个数,我们应该重新考虑整个方法。也许逐位扫描到d[M*2]
中,然后从“右边”形成bytes[]
,或者:
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
很多可能性。
答案 1 :(得分:1)
根据问题和OP注释判断,您需要较小的占用空间,并且不会使用数字进行打印以外的任何操作。
然后,为什么不使用相同的技术来获取uint64_t
中的前18位数字和uint8_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)。
答案 2 :(得分:0)
我的最终解决方案如下。我最终得到了一个位字段结构,因为事实证明我需要在其他地方使用前6位数字。此外,它正在具有newlib nano
的嵌入式系统上运行,该系统不支持64位格式,因此我无法扫描/打印uint64_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;
}