理解内存地址的值
Making Sense Of Values At Memory Addresses
出于好奇,我写了一个非常简单的程序来读取单元素数组前后的前 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 long 可能是合适的(64 位 int)。
我没有使用 "%d"
因为 int 太小会给我 -ve 个值,而且 "%x"
或 "%o"
也会因超出unsigned int
的大小 - 例如,我会得到 ffff...
,其中 int
会读取 -ve 值。
我知道这基本上是 U.B. 就 C 标准而言,但没有什么是真正随机的,所以我想知道可能原因:
- 某些值,例如
127
、0
,始终如一地重复
- 大多数显示的值都是 8/10 位数字,这些数字是固定的:
4294967...
- 一些看似随机的 2 位或 3 位数字值漂浮在这个大数字的海洋之间,例如
123
、18
、55
、96
...
我不是在问为什么会出现这些 exact 值,那是不可能回答的,我是在问为什么 general pattern 的 0
s,8-10 位数字(有 7 个普通数字?)和一些看起来正常的 2-3 位数字值出现,还有 如何理解这些值?
此外,仅 运行 在 MacOSX 上使用此功能(尚未尝试 Windows),并使用 "%c"
,在 ' 求转发',它returns实际字符是这样的:
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,因为它越界访问内存,但您更有可能打印内存中实际存储的内容。
您可以为 []
运算符使用负值,当您有一个指针指向数组的中间或末尾并且负值仍在数组内时,这是明确定义的。它不是你的情况,因为它不再在数组内但它仍然有效。您可以将两个循环合并为一个循环。
出于好奇,我写了一个非常简单的程序来读取单元素数组前后的前 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 long 可能是合适的(64 位 int)。
我没有使用 "%d"
因为 int 太小会给我 -ve 个值,而且 "%x"
或 "%o"
也会因超出unsigned int
的大小 - 例如,我会得到 ffff...
,其中 int
会读取 -ve 值。
我知道这基本上是 U.B. 就 C 标准而言,但没有什么是真正随机的,所以我想知道可能原因:
- 某些值,例如
127
、0
,始终如一地重复 - 大多数显示的值都是 8/10 位数字,这些数字是固定的:
4294967...
- 一些看似随机的 2 位或 3 位数字值漂浮在这个大数字的海洋之间,例如
123
、18
、55
、96
...
我不是在问为什么会出现这些 exact 值,那是不可能回答的,我是在问为什么 general pattern 的 0
s,8-10 位数字(有 7 个普通数字?)和一些看起来正常的 2-3 位数字值出现,还有 如何理解这些值?
此外,仅 运行 在 MacOSX 上使用此功能(尚未尝试 Windows),并使用 "%c"
,在 ' 求转发',它returns实际字符是这样的:
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,因为它越界访问内存,但您更有可能打印内存中实际存储的内容。
您可以为 []
运算符使用负值,当您有一个指针指向数组的中间或末尾并且负值仍在数组内时,这是明确定义的。它不是你的情况,因为它不再在数组内但它仍然有效。您可以将两个循环合并为一个循环。