首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C中将uint32_t转换为二进制

问在C中将uint32_t转换为二进制
EN

Stack Overflow用户
提问于 2022-09-03 17:13:32
回答 2查看 362关注 0票数 -1

我面临的主要问题是读取C. Python中的二进制值,C#有一些非常快速/简单的函数来实现这一点,我找到了关于如何在C++中这样做的主题,我找到了关于如何在C中将int转换为二进制的主题,但在C中没有找到如何将uint32_t转换为二进制的主题。

我要做的是一点一点地读取DR_REG_RNG_BASE地址的32位(这是存储ESP32的随机硬件生成器的随机值的地址)。

所以现在我做的是:

代码语言:javascript
复制
#define DR_REG_RNG_BASE                        0x3ff75144

void printBitByBit( ){

    // READ_PERI_REG is the ESP32 function to read DR_REG_RNG_BASE
    uint32_t rndval = READ_PERI_REG(DR_REG_RNG_BASE);
    int i;
    for (i = 1; i <= 32; i++){ 
      int mask =  1 << i;
      int masked_n = rndval & mask;
      int thebit = masked_n >> i;   
      Serial.printf("%i", thebit);
    }
    Serial.println("\n");
}

一开始我觉得效果很好。但事实上,它使我脱离了完全错误的二进制表示。有什么想法吗?

EN

回答 2

Stack Overflow用户

发布于 2022-09-03 17:46:55

显示的代码存在许多错误/问题。

首先,uint32_t ( 32位无符号整数)的位位置是基于零的-所以,它们从0到31运行,而不是从1到32运行,正如您的代码所假设的那样。因此,在您的代码中,您(实际上)忽略了最低位(位#0);此外,当您在最后一个循环上执行1 << i (当i == 32时),您的掩码将(很可能)有一个值为零(尽管从技术上讲,这种转换是符号整数的未定义行为,正如您的代码使用的那样),所以您也将删除最高位。

其次,您的代码首先打印最低位(从左到右),但您希望(大概)按照正常情况先打印最高位。因此,您应该运行循环,i索引从31开始,并将其降为零。

此外,您的代码混合和混合无符号和有符号整数类型。最好避免这种情况,所以最好对循环中使用的中间值使用uint32_t。

最后(正如Eric在注释中提到的),从无符号整数中提取“位n”的方法要简单得多:只需使用value >> n & 1即可。

我无法访问Arduino平台,但是,为了演示在上述讨论中提出的要点,下面是一个标准的控制台模式C++程序,它将代码的输出与上述更正进行比较:

代码语言:javascript
复制
#include <iostream>
#include <cstdint>
#include <inttypes.h>

int main()
{
    uint32_t test = 0x84FF0048uL;
    int i;
    // Your code ...
    for (i = 1; i <= 32; i++) {
        int mask = 1 << i;
        int masked_n = test & mask;
        int thebit = masked_n >> i;
        printf("%i", thebit);
    }
    printf("\n");
    // Corrected limits/order/types ...
    for (i = 31; i >= 0; --i) {
        uint32_t mask = (uint32_t)(1) << i;
        uint32_t masked_n = test & mask;
        uint32_t thebit = masked_n >> i;
        printf("%"PRIu32, thebit);
    }
    printf("\n");
    // Better ...
    for (i = 31; i >= 0; --i) {
        printf("%"PRIu32, test >> i & 1);
    }
    printf("\n");
    return 0;
}

三行输出(第一条错误,如你所知;最后两条正确)是:

代码语言:javascript
复制
001001000000000111111110010000-10
10000100111111110000000001001000
10000100111111110000000001001000

备注:

(1)关于使用外观滑稽的"%"PRu32格式说明符打印uint32_t类型,请参见:printf format specifiers for uint32_t and size_t。

(2)对(uint32_t)(1)常数的转换将确保比特移位是安全的,即使int和unsigned是16位类型;如果没有这种类型,在这种情况下您将得到未定义的行为。

票数 1
EN

Stack Overflow用户

发布于 2022-09-07 03:55:30

当您打印出一个数字的二进制字符串表示时,首先打印最有意义的位( MSB ),无论该数字是uint32_t还是uint16_t,因此您需要一个掩码来检测MSB是1还是0,因此您需要一个0x80000000掩码,并在每次迭代中进行移位。

代码语言:javascript
复制
#define DR_REG_RNG_BASE                        0x3ff75144

void printBitByBit( ){

    // READ_PERI_REG is the ESP32 function to read DR_REG_RNG_BASE
    uint32_t rndval = READ_PERI_REG(DR_REG_RNG_BASE);

    Serial.println(rndval, HEX);   //print out the value in hex for verification purpose

    uint32_t mask = 0x80000000;
    for (int i=1; i<32; i++) {
      Serial.println((rndval & mask) ? "1" : "0");
      mask = (uint32_t) mask >> 1;
    }
    Serial.println("\n");

}

对于Arduino,实际上有两个内置函数可以打印出一个数字的二进制字符串表示形式。Serial.print(x, BIN)允许您根据第二个函数参数指定数字。

另一个可以实现相同结果的函数是itoa(x, str, base),它不是标准ANSI或C++的一部分,但在Arduino中可用,以允许您将数字x转换为指定数字基的str。

代码语言:javascript
复制
char str[33];
itoa(rndval, str, 2);
Serial.println(str);

但是,这两个函数都没有带前导零的pad,请参见这里的结果:

代码语言:javascript
复制
36E68B6D                          // rndval in HEX
00110110111001101000101101101101  // print by our function
110110111001101000101101101101    // print by Serial.print(rndval, BIN)
110110111001101000101101101101    // print by itoa(rndval, str, 2)

顺便说一下,Arduino是c++,所以不要在帖子中使用c标记。我给你换的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73594091

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档