如何在 C 中转储变量的位?[复制]

How to dump a variable's bits in C? [duplicate]

提问人:Virgil G. 提问时间:7/21/2023 最后编辑:Virgil G. 更新时间:7/22/2023 访问量:94

问:

我正在尝试对函数进行编码:

void memdump(void *p, size_t nmemb, size_t size);

其目的是以正确的顺序显示 所指向的变量中包含的位。不检查是否是故意的。也使用。ppNULLwrite()

问题是我希望显示器是正确的,无论机器的长度如何。

这是我的代码:

#include <unistd.h>
#include <stdint.h>

void memdump(void *p, size_t nmemb, size_t size)
{
    size_t total_bits = nmemb * size * 8;
    unsigned char *ptr = (unsigned char *)p;

    for (size_t i = 0; i < total_bits; i++) {
        unsigned char bit = (ptr[i / 8] >> (7 - (i % 8))) & 0x01;
        char c = bit ? '1' : '0';
        write(STDOUT_FILENO, &c, sizeof(char));
        if ((i + 1) % 8 == 0)
            write(STDOUT_FILENO, " ", 1);
    }
    write(STDOUT_FILENO, "\n", sizeof(char));
}

int main(void)
{
    int i = 0;
    int j[2] = {1, 0};
    char c = 'a';
    char *s = "za";
    uint64_t size = 213213;

    memdump(&i, 1, sizeof(int));
    memdump(j, 2, sizeof(int));
    memdump(&c, 1, sizeof(char));
    memdump(s, 2, sizeof(char));
    memdump(&size, 1, sizeof(size_t));
    return 0;
}

因此,我期望以下结果:

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001 00000000 00000000 00000000 00000000
01100001
01111010 01100001
00000000 00000000 00000000 00000000 00000000 00000011 01000000 11011101

但我明白了:

00000000 00000000 00000000 00000000 
00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
01100001 
01111010 01100001 
11011101 01000000 00000011 00000000 00000000 00000000 00000000 00000000 

你可以帮我吗?

下面是一个可重现示例的链接:https://onlinegdb.com/4e5Ei2OUS

提前致谢

[更新]

我不知道如何考虑内延性,这是我的问题。 我的 memdump 函数应该具有上面指定的预期行为。

我不检查指针是否为 NULL 的原因很简单,因为这个函数是基于标准 C 库及其原理的库的一部分(即开发人员对他们的代码负责,所以将 NULL 字符串传递给 strlen(),你不会收到任何警告)。

我的函数应该按照字节插入变量示例的顺序显示字节:

int test[2] = {0 , 1};

预期结果是:

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001

机器的无端序并不重要。

C Linux glibc

评论

5赞 jarmod 7/21/2023
你试图在哪里解释“机器的endianess”?
4赞 Eric Postpischil 7/21/2023
@datenwolf:关于不检查是否故意的评论旨在通知您,已做出不执行此类检查的选择,确保未传递空指针是调用方的责任,并且此问题不是问题的一部分,不需要讨论或评论。NULLmemdump
1赞 John Bollinger 7/21/2023
众所周知,@EricPostpischil、左移和右移是根据语义值定义的,而不是存储中的表示。否则,它们的影响将取决于字节序。
3赞 John Bollinger 7/21/2023
根据更新,您希望输出独立于机器的整数表示(字节序),但这很难与函数的通用签名相协调。是否假设所有输入都是整数数组,每个数组的大小都由 ?请注意,这不会直接支持结构或联合或指针或浮点类型。如果希望输出反映对象的语义值,则可能需要更明确地考虑数据类型的代码。nmembsize
3赞 Ben Voigt 7/21/2023
简单地说,你的期望是错误的,因为你对“字节在变量中出现的顺序”的信念是错误的。

答:

1赞 KamilCuk 7/22/2023 #1

预期结果是:

1
00000000 00000000 00000000 00000001

最重要的位在左边。左边是地址最低的字节。这意味着最大(即“大”)有效位具有最低地址。所以这是大端序。阅读 https://en.wikipedia.org/wiki/Endianness

如何考虑内延性

应用动态规划。两个步骤:


nmemb * size * 8;

考虑使用 limits.h 中的CHAR_BITS

memdump(&i, 1, sizeof(int));

请考虑使用 和 以防更改变量类型。sizeof(i)sizeof(*j)

char *s = "za";

请注意,endianess 对 和 的顺序没有影响。 总是首先(具有最低地址),然后是 ,然后是零字节。您可以考虑选择性地应用字节变换。zaza

而且,还要注意,在 linux 和 C23 中使用最新的 glibc,我们必须打印二进制文件!耶!printf("%b", 123);

评论

1赞 n. m. could be an AI 7/22/2023
动态规划?真?