为什么我们不能在 C 或 C++ 代码中使用直接寻址?

Why can't we use direct addressing in c or c++ code?

本文关键字:直接寻址 代码 C++ 不能 我们 为什么      更新时间:2023-10-16

当我连续编译并执行这段代码几次时,它将cc的地址报告为0x0012FF5C。但是当我尝试使用在 foo 中第二次调用 printf 来打印该地址的字符串时,它会打印垃圾而不是打印出"Hello"??为什么会这样??如果我知道地址位于应用程序的地址空间内时,我直接将地址作为参数(至少在我不重新启动PC或启动其他需要大量空间并导致我的应用程序被分页的应用程序之前)有什么问题??

void foo(char *cc[])
{
    printf("%xn",cc);
    printf("%sn",(char *)(0x0012FF5C));
}
int main()
{
    char *c[] = {"Hello","World"};
    foo(c);
}

因为 C 或 C++ 标准中没有任何内容可以保证这一点。 这些地址可能是可预测的,具体取决于您的编译器/操作系统,但不要指望它。

#include <stdio.h>
int main(void) {
    char s[] = "okay";
    printf("%p", (void*)s);
    return 0;
}  

每次都会得到一个不同的地址(linux上的gcc)。 不要使用"地址文字";)

现代操作系统上的进程地址空间是随机的,以确保每次执行的安全性:

http://en.wikipedia.org/wiki/Address_space_layout_randomization

因为当第二个 printf 尝试将此 char* 数组打印为字符串时,第一个 printf 会为您提供 char* 数组的地址。

好的,第一件事是,永远不要假设多个执行将返回相同的地址

现在,假设您很幸运并获得了相同的地址。请注意,cc是一个指针数组。您正在发送此数组的基址。您需要发送数组第一个元素的值

试试这个,如果你幸运的话,它有效,

printf("%sn",*((char**)(0x0012FF5C)));

如果您在没有虚拟内存和内存保护的计算机上运行程序,则很可能会成功。这些技术/功能是它不起作用的原因。

每个进程都有自己的虚拟地址空间,其地址由处理器的内存管理单元转换为硬件地址。

我不认为你的(0x0012FF5C)代表poiter。尝试 (字符*)(0x0012FF5C)。

除此之外,就像其他人告诉你的那样,这没有实际价值,因为不能保证每次运行都会在该地址找到字符串。这不是一些嵌入式程序集,您说将此字符串放在此位置,然后直接使用该地址。

进程的内存位置可能在两次执行之间发生了更改。你不能那样做,你试图阅读一个没有被你的过程分配的地址。此外,我有很多警告:

test.c:在函数 'foo' 中: test.c:6: 警告:格式 '%x' 需要类型'unsigned int',但参数 2 的类型为 'char **'

test.c:7:警告:格式"%s"需要类型"char *",但参数 2 的类型为"int"

test.c:9:警告:格式"%x"需要类型"无符号整数",但参数 2 的类型为"char **"

当我知道地址

好吧,当你对地址

进行硬编码时,你对地址一无所知,你是在猜测它。

事物

的地址在执行同一程序之间可能会发生变化的原因有很多。如果您正在更改代码,地址可能会更改的原因还有更多(就像您在此处所做的那样)。

正如之前有人所说,您在内存中的代码位置可能会因执行而异,变量的位置也会发生同样的情况。尝试运行此代码。它打印您在内存中指向的变量的实际地址。 您将看到多个执行会产生完全不同的地址。永远记住这一点!

 #include <stdio.h>
 void foo(char *cc[])
{
    printf("%xn",cc);
    printf("%sn",(0x0012FF5C)); //this line will fail, there is no guarantee to that
    cc++;
    printf("%xn",cc);
}
int main()
{
    char *c[] = {"Hello","World"};
    printf("c array location: %p",c); //print location
    foo(c);
}

首先,printf("%xn",cc);不打印cc的地址。充其量它打印 cc 的值,但行为是未定义的,因为您为格式传递了错误的类型参数 %x 。它期望unsigned int,您已经提供了一个指针。

在实践中最可能的行为是它将打印cc值中最不重要的部分(因此在 32 位计算机上它看起来可以工作,而在 64 位计算机上,您不会看到整个地址)。但它可能会以不同的方式出错。

第二件事,cc具有类型 char** ,因此 cc 的值不是指向字符串第一个字符的指针,而是指向数组的第一个元素的指针,c来自main%s格式需要一个指向字符串第一个字符的指针。因此,即使cc的值确实是0x0012FF5C,将该值传递给具有%s格式的printf也是错误的。

您看到的"垃圾"是尝试从该指针数组打印指针数据,就好像它是属于字符串的字符数据一样。其实不然。

我稍微

简化了你的例子。如果您知道字符串的地址,则可以从该地址读取。

#include <stdio.h>
void foo(char cc[])
{
    int i;
    printf("%pn",cc);
    printf("Type the address you would like to read:");
    scanf ("%x",&i);
    printf("Character value at your address: %cn",*((char *)(i)));
}
int main()
{
    char c[] = "Hello";
    foo(c);
}

这将允许您从命令行指定的地址读取。它将首先打印出字符数组的基址,以便您知道在哪里查找字符串。

例:

$ ./a.out 
0xbfcaaf3a
Type the address you would like to read:bfcaaf3d
Character value at your address: l

不出所料,这打印了Hello的第四个字母。