如何在C语言中打印内存位

7

我正在学习数字在内存中的表示方式。我想知道如何打印一些整型和浮点型变量在内存中的实际表示(二进制或十六进制)。

例如,当加减操作导致溢出时,我想看看这些数字会发生什么。

我该如何访问内存并将其打印出来?


使用访问说明符%uprintf()函数。 - Jaffer Wilson
如果其中一个答案解决了您的问题,请考虑接受它 - dbush
6个回答

11

你需要将指针分配给相关变量的char *,并将其视为长度为sizeof(variable)的字节数组。然后可以使用%X格式说明符将每个字节以十六进制形式打印到printf中。

您可以像这样定义一个函数:

void print_bytes(void *ptr, int size) 
{
    unsigned char *p = ptr;
    int i;
    for (i=0; i<size; i++) {
        printf("%02hhX ", p[i]);
    }
    printf("\n");
}

并且这样调用:

int x = 123456;
double y = 3.14;
print_bytes(&x, sizeof(x));
print_bytes(&y, sizeof(y));

应该将其改为 unsigned char 并使用 %hhX 作为格式说明符。 - John Bode
@JohnBode 好主意。已编辑。 - dbush
@dbush,你的示例打印出40 E2 01 00(int 123456 -> 32位)。我认为应该是00 01 E2 40。这是因为内存如何存储数字?还是我应该修改循环? - aledruetta
1
@AleD 这是由于你的机器的字节序(即整数类型的字节顺序)导致的。现在大多数机器(就像这个例子一样)都是小端序,也就是最不重要的字节排在最前面。如果你在 Sun 机器上运行它,那么你会看到最重要的字节排在最前面。 - dbush

4

...打印实际表示(二进制...

任何/所有变量/对象转换为编码二进制形式的字符串,需要使用一个帮助函数将内存转换为“二进制”字符串。此方法还处理函数指针。 使用C99或更高版本。

#include <stdio.h>
#include <assert.h>
#include <limits.h>

//                                    .... compound literal .......
#define VAR_TO_STR_BIN(x) obj_to_bin((char [sizeof(x)*CHAR_BIT + 1]){""}, &(x), sizeof (x))

char *obj_to_bin(char *dest, void *object, size_t osize) {
  const unsigned char *p = (const unsigned char *) object;
  p += osize;
  char *s = dest;
  while (osize-- > 0) {
    p--;
    unsigned i = CHAR_BIT;
    while (i-- > 0) {
      *s++ = ((*p >> i) & 1) + '0';
    }
  }
  *s = '\0';
  return dest;
}

int main(void) {
  int i = 42;
  double d = 3.1415926535897932384626433832795;
  printf("Sample\ndouble pi:%s\nint 42:%s\n", VAR_TO_STR_BIN(d), VAR_TO_STR_BIN(i) );
  return 0;
}

输出(注意:根据字节序的不同,结果可能会有所不同)

Sample
double pi:0100000000001001001000011111101101010100010001000010110100011000  
int 42:00000000000000000000000000101010

这种方法很容易适应十六进制形式。


你好!你能解释一下"(char [sizeof(x)*CHAR_BIT + 1]){""}"这段代码吗?我不明白为什么要加上"+1"和"{""}" :/ - Hedwin Bonnavaud
@HedwinBonnavaud 你对复合字面量有多熟悉?存储字符串“00001111”所需的内存大小是8还是9? - chux - Reinstate Monica
明白了,你是要加上 +1 的来保留字符串末尾的 '\0' 吗? - Hedwin Bonnavaud
1
@HedwinBonnavaud 是的,对于“空字符”+1。 - chux - Reinstate Monica
好的,谢谢你提供这个漂亮且有用的代码。顺便说一句。 - Hedwin Bonnavaud

2
调用print_bits(变量的内存地址, 变量大小(字节))
void print_bits(void *ptr, int size) //ptr = memory address of variable, size = size of variable in byte
{
    long long *ch = ptr;
    int size_bits = size * 8;
    for(int i = size_bits-1; i>=0; i--){
        printf("%lld", *ch >> i & 1) ;
    }
}

这已经成功测试,可以处理任何小于或等于64位的变量。对于其他大小的变量(未测试),可能会正常工作。

调用:

double d = -7.92282286274e+28;
print_bits(&d, sizeof(d));

输出:

1100010111110000000000000000000011100000000000000000000100010111

1
假设您有一个名为memory的int变量。请确保您知道它有多少位; 对于许多处理器,int是32位以及内存地址。因此,您需要遍历每个位,如下所示:
unsigned int memory = 1234;
for (int i = 0; i < 32; i++)
{
  printf("%d ", memory >> i & 1);
}

这个简单的方法将每个位与1进行或运算,并将每个位向左移动1位。

更好地使用带有商和余数的while循环来避免处理器位问题。 - Yoon-Geun Kwon
@Yoon-GeunKwon:移位操作不依赖于字节或位顺序。根据C11草案标准6.5.7位移操作符,它在数学上被定义为2的n次幂的除法/乘法。 - EOF
这里假设是32位整型,但这并不一定正确。 - Mr. E

1
#include <stdio.h>
#include <stdlib.h>

void print_bits ( void* buf, size_t size_in_bytes )
{
    char* ptr = (char*)buf;

    for (size_t i = 0; i < size_in_bytes; i++) {
        for (short j = 7; j >= 0; j--) {
            printf("%d", (ptr[i] >> j) & 1);
        }
        printf(" ");
    }
    printf("\n");
}

int main ( void )
{
    size_t n;
    scanf("%d", &n);
    print_bits(&n, sizeof(n));
    return 0;
}

这将以指定大小(以字节为单位)打印指定对象的位(此处为n)。


1
@dbush,@Anton,我混合了你们的代码。可以吗?
#include <stdio.h>
#include <stdlib.h>

void print_bytes( void *ptr, size_t size ) ;

int main( void )
{
    int x = 123456 ;
    double y = 3.14 ;

    print_bytes( &x, sizeof(x) ) ;
    print_bytes( &y, sizeof(y) ) ;

    return 0 ;
}

void print_bytes( void *ptr, size_t size )
{
    //char *buf = (char*) ptr;
    unsigned char *p = ptr ;

    for( size_t i = 0; i < size; i++ )
    {
        printf( "%02hhX ", p[i] ) ;
    }
    printf( "\n" ) ;

    for( size_t i = 0; i < size; i++ )
    {
        for( short j = 7; j >= 0; j-- )
        {
            printf( "%d", ( p[i] >> j ) & 1 ) ;
        }
        printf(" ");
    }
    printf("\n");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接