【问题标题】:fetch data from a variables memory address one byte at a time从变量内存地址中获取数据,一次一个字节
【发布时间】:2013-11-02 13:55:08
【问题描述】:

我有一小段代码试图演示各种标准整数 类型并显示内存似乎分配在最大的堆栈中 首先是数据类型。我写的东西似乎是合理的,直到我得到方法的最后一行 输出字节数过多。我真的只是想要(并且期望)只得到一个字节。

因此:

#include <stdint.h>  /* defines the standard integer types */
#include <stdio.h>   /* defines all the IO functions */
#include <stddef.h>  /* standard definitions */
#include <stdlib.h>  /* standard library functions */

int main ( int argc, char *argv[] ) {

    int8_t  little_i = 11;
    int16_t med_i = 12062;
    int32_t norm_i = 1991;
    int64_t big_i = -3245321806; 

    /* these next items are pointers */
    int8_t *little_p; 

    printf ( "here is a little  8-bit int : little_i = %02x\n", little_i );
    printf ( "here is a medium 16-bit int : med_i    = %04x\n", med_i );
    printf ( "here is a normal 32-bit int : norm_i   = %08x\n", norm_i );
    printf ( "here is a big    64-bit int : big_i    = %016lx\n", big_i );

    printf ( "addr of little_i is %p" , &little_i );  
    printf ( " and the size is %d\n" , sizeof(little_i) );
    printf ( "addr of med_i    is %p" , &med_i );  
    printf ( " and the size is %d\n" , sizeof(med_i) );
    printf ( "addr of norm_i   is %p" , &norm_i );   
    printf ( " and the size is %d\n" , sizeof(norm_i) );
    printf ( "addr of big_i    is %p" , &big_i );   
    printf ( " and the size is %d\n" , sizeof(big_i) );

    /* tell us about the pointer */
    printf ( "\n--------------------------------------------------\n" );
    printf ( " size of the pointer little_p is %d\n" , sizeof(little_p) );
    printf ( " the address of the pointer itself is %p\n", &little_p );

    little_p = &little_i;

    printf ( "\nthe pointer little_p now contains the addr %p\n", little_p );
    printf ( "The data there, in memory, at the addr %p is 0x%02xh\n",
                         little_p, *little_p );

    /* we can point a pointer anywhere we want */
    little_p = (void *) &big_i;

    printf ( "\n\nthe pointer little_p now has the addr %p\n", little_p );

    printf ( "The data there, in memory, at the addr is 0x%02xh\n",
                                                    *( (int8_t*) little_p) );

    return ( EXIT_SUCCESS );
}

直到最后一行,我得到的输出看起来都很棒:

$ ./dtypes
here is a little  8-bit int : little_i = 0b
here is a medium 16-bit int : med_i    = 2f1e
here is a normal 32-bit int : norm_i   = 000007c7
here is a big    64-bit int : big_i    = ffffffff3e9051b2
addr of little_i is ffffffff7ffff56b and the size is 1
addr of med_i    is ffffffff7ffff568 and the size is 2
addr of norm_i   is ffffffff7ffff564 and the size is 4
addr of big_i    is ffffffff7ffff558 and the size is 8

--------------------------------------------------
 size of the pointer little_p is 8
 the address of the pointer itself is ffffffff7ffff550

the pointer little_p now contains the addr ffffffff7ffff56b
The data there, in memory, at the addr ffffffff7ffff56b is 0x0bh


the pointer little_p now has the addr ffffffff7ffff558
The data there, in memory, at the addr is 0xffffffffh

我希望在最后一行只看到一个字节 0xffh,但得到了一个完整的 32 位整数大小的结果。我认为将 little_p 转换为 int8_t* 类型的指针可以解决问题。

我错过了什么明显的东西吗?

----- 在我发布这个问题后更新:

我将最后一行更改为 uint8_t* :

    printf ( "The data there, in memory, at the addr is 0x%02xh\n",
                                                *( (uint8_t*) little_p) );

这给了我输出:

The data there, in memory, at the addr is 0xffh

主要是因为内存中的字节一次是无符号的 8 位。

看起来很合理。

----------- 进一步编辑以从 64 位整数中提取和打印字节 ------

这是一个更新的代码块:

$ cat dtypes.c
#include <stdint.h>  /* defines the standard integer types */
#include <stdio.h>   /* defines all the IO functions */
#include <stddef.h>  /* standard definitions */
#include <stdlib.h>  /* standard library functions */

int main ( int argc, char *argv[] ) {

    int8_t  little_i = 11;
    int16_t med_i = 12062;
    int32_t norm_i = 1991;
    int64_t big_i = -3245321806; 

    void *little_p; /* void datatype is no datatype at all really. */

    printf ( "here is a little  8-bit int : little_i = %02x\n", little_i );
    printf ( "here is a medium 16-bit int : med_i    = %04x\n", med_i );
    printf ( "here is a normal 32-bit int : norm_i   = %08x\n", norm_i );
    printf ( "here is a big    64-bit int : big_i    = %016lx\n", big_i );

    printf ( "addr of little_i is %p" , &little_i );  
    printf ( " and the size is %d\n" , sizeof(little_i) );
    printf ( "addr of med_i    is %p" , &med_i );  
    printf ( " and the size is %d\n" , sizeof(med_i) );
    printf ( "addr of norm_i   is %p" , &norm_i );   
    printf ( " and the size is %d\n" , sizeof(norm_i) );
    printf ( "addr of big_i    is %p" , &big_i );   
    printf ( " and the size is %d\n" , sizeof(big_i) );

    /* tell us about the pointer */
    printf ( "\n--------------------------------------------------\n" );
    printf ( " size of the pointer little_p is %d\n" , sizeof(little_p) );
    printf ( " the address of the pointer itself is %p\n", &little_p );

    /* we can point a pointer anywhere we want */
    little_p = (void *) &big_i;

    printf ( "\n\nthe pointer little_p now has the addr %p\n", little_p );

    printf ( "The data there, in memory, at the addr is 0x%02xh\n",
                                               *( (uint8_t*) little_p) );

    printf ( "                             at addr+1 is 0x%02xh\n",
                                               *( (uint8_t*) little_p+1 ) );

    printf ( "                             at addr+2 is 0x%02xh\n",
                                               *( (uint8_t*) little_p+2 ) );

    printf ( "                             at addr+3 is 0x%02xh\n",
                                               *( (uint8_t*) little_p+3 ) );

    printf ( "                             at addr+4 is 0x%02xh\n",
                                               *( (uint8_t*) little_p+4 ) );

    printf ( "                             at addr+5 is 0x%02xh\n",
                                               *( (uint8_t*) little_p+5 ) );

    printf ( "                             at addr+6 is 0x%02xh\n",
                                               *( (uint8_t*) little_p+6 ) );

    printf ( "                             at addr+7 is 0x%02xh\n",
                                               *( (uint8_t*) little_p+7 ) );

    return ( EXIT_SUCCESS );
}

这给出了非常好的结果:

$ ./dtypes
here is a little  8-bit int : little_i = 0b
here is a medium 16-bit int : med_i    = 2f1e
here is a normal 32-bit int : norm_i   = 000007c7
here is a big    64-bit int : big_i    = ffffffff3e9051b2
addr of little_i is ffffffff7ffff56b and the size is 1
addr of med_i    is ffffffff7ffff568 and the size is 2
addr of norm_i   is ffffffff7ffff564 and the size is 4
addr of big_i    is ffffffff7ffff558 and the size is 8

--------------------------------------------------
 size of the pointer little_p is 8
 the address of the pointer itself is ffffffff7ffff550


the pointer little_p now has the addr ffffffff7ffff558
The data there, in memory, at the addr is 0xffh
                             at addr+1 is 0xffh
                             at addr+2 is 0xffh
                             at addr+3 is 0xffh
                             at addr+4 is 0x3eh
                             at addr+5 is 0x90h
                             at addr+6 is 0x51h
                             at addr+7 is 0xb2h

这里一切似乎都很好。

【问题讨论】:

    标签: c


    【解决方案1】:

    这是因为地址处的数据是0xff,所以它的符号位有1。这意味着数据在转换为int 时进行符号扩展,这在将值传递给printf 时发生。符号扩展意味着用原始值的符号位填充int 的缺失字节。在这种情况下,这意味着用 1 填充其余位,从而生成 Fs (demo 1) 字符串。

    将格式更改为%hhx 将解决问题(demo 2;谢谢Martin R!)。

    【讨论】:

    • 我自己也发现了。必须记得在早上做第一杯咖啡,然后在我发布之前思考......但这对我来说可能是一个合理的教训。内存不是签名数据。它只是记忆。
    • 也 .. 喜欢你的用户名。是的,我记得我们有很大的计算机控制室和很多闪烁的灯:-)
    • @paullanken:另请注意,以十六进制打印字符大小的数量的格式是%hhx,而不是%xh。无论签名如何,更改格式也会产生预期的输出。
    • @MartinR:有趣。我从来没有用过。我刚刚检查了 printf(3C) 的手册页,果然有一些东西可以用于 hh。我一直认为可以使用 %02x 以十六进制打印单个字节。
    • @MartinR 感谢您的精彩评论 - 我编辑了答案以反映它。
    【解决方案2】:

    尝试转换为 (uint8_t*),您的字节的值为 0xff,在十进制中为 -1,它将被符号扩展为 32 位,因此最终为 0xffffffffh(再次以二进制补码表示法 -1)。所以对无符号数据使用无符号类型。

    【讨论】:

      猜你喜欢
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多