Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将大整数扫描(sscanf)为字节_C_Scanf - Fatal编程技术网

将大整数扫描(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个字节。我现在需要移动两个变量,而不是一个。为了澄清,它不是用来打印的(我只是把它作为一个最低限度的例子)。最终结果将通过蓝牙低能量发送到另一个设备。这只是存储信息。理论上,它可以被存储