【问题标题】:Why can't we use direct addressing in c or c++ code?为什么我们不能在 c 或 c++ 代码中使用直接寻址?
【发布时间】:2012-10-04 03:25:47
【问题描述】:

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

void foo(char *cc[])
{
    printf("%x\n",cc);
    printf("%s\n",(char *)(0x0012FF5C));
}

int main()
{
    char *c[] = {"Hello","World"};
    foo(c);
}

【问题讨论】:

  • 您为什么要这样做,因为您只是在对冲使用相同地址的赌注?做一点改变,你就破坏了代码。似乎很愚蠢的事情要做甚至考虑。
  • 请不要删除已回答的问题。有人努力回答你的问题。

标签: c++ c pointers


【解决方案1】:

因为 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

【讨论】:

  • 您应该强制转换为 void* 您的地址是标准的。
  • 嗯。 -Wall -pedantic 什么也没说,但你是对的,C99 草案对 fprintf 说“p 参数应是指向 void 的指针”。已编辑。
  • @Kirilenko: 是否没有任何从T*void* 的隐式转换
  • @David Rodríguez:它不适用于此示例,因为printf 采用可变数量的参数,在编译时不检查其类型(因此不执行自动转换)。
【解决方案2】:

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

【讨论】:

  • 是的,cc 需要被取消引用才能获得指向实际字符串开头的指针。
【解决方案3】:

好的,首先,永远不要假设多次执行会返回相同的地址

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

试试这个,如果你幸运的话,

printf("%s\n",*((char**)(0x0012FF5C)));

【讨论】:

  • 嗯...基地址的值和第一个元素的值将是相同的。
  • @user1232138 检查我的编辑! 基地址和值不相同。解引用基地址和基地址处的值是一样的
【解决方案4】:

如果你在没有virtual memorymemory protection 的机器上运行你的程序,你很可能会成功。这些技术/功能是它不起作用的原因。

每个进程都有自己的虚拟地址空间,其地址由处理器的memory-management unit 转换为硬件地址。

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

      您的进程的内存位置可能在两次执行之间发生了变化。你不能这样做,你正在尝试读取一个没有被你的进程分配的地址。此外,我有很多警告:

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

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

      test.c:9:警告:格式“%x”需要类型“unsigned int”,但参数 2 的类型为“char **”

      【讨论】:

        【解决方案7】:

        当我知道地址时

        好吧,当您对地址进行硬编码时,您对地址一无所知知道,您只是在 猜测

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

        【讨论】:

          【解决方案8】:

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

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

          【讨论】:

            【解决方案9】:

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

            在实践中最可能的行为是它会打印cc 值的最低有效部分(因此在 32 位机器上它似乎可以工作,而在 64 位机器上你不会看到整个地址)。但它可能会以不同的方式出错。

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

            您看到的“垃圾”是试图从该指针数组中打印指针数据,就好像它是属于字符串的字符数据一样。不是。

            【讨论】:

              【解决方案10】:

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

              #include <stdio.h>
              
              void foo(char cc[])
              {
                  int i;
                  printf("%p\n",cc);
                  printf("Type the address you would like to read:");
                  scanf ("%x",&i);
                  printf("Character value at your address: %c\n",*((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 的第四个字母。

              【讨论】:

              • 为什么我们不能使用该地址来打印整个字符串?
              • @user1232138:你可以。将 foo 的最后一行更改为printf("Character value at your address: %s\n",(char *)(i));
              • @user1232138:你的意思是它不起作用?怎么了?我刚刚对其进行了测试,它确实有效。
              • 它异常终止说“某些指令”引用了“某个内存位置”,无法读取。我使用的是 32 位操作系统 (winXP),如果有问题的话..
              猜你喜欢
              • 2015-01-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-06-12
              相关资源
              最近更新 更多