了解内存地址的值

问题描述

出于好奇,我编写了一个非常简单程序,以读取单元素数组前后的前1000个字节,以查看要获得的值以及生成的值其中

#include <stdio.h>

int main(){
    char mem[1];
    printf("\n\tSeeking Ahead...\n\t %lld to %lld\n\n",mem,mem+1000);

    for(int i=0; i <= 1000; i++)
        printf("%lld ",mem[i]);

    printf("\n\n\tSeeking Behind...\n\t %lld to %lld\n\n",mem-1000,mem);

    for(int i=1000; i >= 0; i--;)
        printf("%lld ",*(mem-i));

    printf("\n\n-------END------\n\n");
    
    return 0;
} 

选择"%lld"的原因是我有一个模糊的想法,即64位系统将具有64位地址,因此,长long可能是合适的(64位int)。

我不使用"%d"是因为int太小会给我-ve值,并且"%x""%o"也会疯狂使用超出一个unsigned int-例如,我会得到ffff...,其中int将读取-ve值。

我知道就C标准而言,这基本上是 U.B。,但是没有什么是真正随机的,因此我想知道为什么的可能原因:

  • 某些值(如1270)重复出现
  • 显示的大多数值都是8/10位数字,这些数字固定为4294967...
  • 一些看似随机的2或3位数字值在这大量数字之间浮动,例如123185596 ...

我不是在问为什么这些 exact 值会出现,这是不可能回答的,我是在问为什么0 s的常规模式 ,出现8-10位数字(带有7个公共数字?)和一些正常的2-3位数字值,以及如何理解这些值?

在MacOSX(尚未尝试Windows)上运行此程序,并使用"%c"在' forwarding '时返回实际字符像这样:

executable_path=./memdump./memdumpTERM_PROGRAM=Apple_TerminalSHELL=/bin/bashTERM=xterm-256colorTMPDIR=/var/folders...

为什么?

解决方法

printf()指示符%lld期望以long long作为参数。如果像您一样提供一个较短的变量,则只需设置此参数的一部分并导致UB,除了导致超出范围访问数组的UB之外(是的,我知道UB是UB,并且没有其他区别UB的形式,但我想解释一下为什么获得了您得到的值)。在AMD64上,该值的高32位可能与该程序的某些随机部分相同(之前设置了所用的寄存器),而char参数仅更改了低32位。 int范围之外的每个值都是由于此错误。 mem[i]是一个字符,然后被提升为int。因此,通常您不会以这种方式获得int范围内的值,而不会得到char范围内的值。

如果要进行该实验,请使用正确的格式说明符,我建议您使用十六进制格式说明符。使用unsigned char也会更聪明。它将仍然是UB,因为它会无限制地访问内存,但是您更有可能打印出实际存储在内存中的内容。

您可以对[]运算符使用负值,当指针指向数组的中间或结尾且负值仍在数组内部时,可以很好地定义此值。情况并非如此,因为它不再位于数组中,但仍然可以使用。您可以将两个循环组合成一个循环。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...