我们可以只使用C中的裸地址打印数据吗?

时间:2017-08-15 15:38:15

标签: c pointers

我想知道我们是否可以仅使用C语言中该位置的裸地址在特定位置打印数据。

例如,以下是我使用的代码:

#include<stdio.h>

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

    int num = 10;
    int *ptr;
    ptr = &num;

    //To output the address of the "num" variable
    printf("Address: %p\n", ptr);

    //Address is 0x7fff47808f50...

    //Using that address to print the data at variable "num"
    printf("Data: %d\n", *(0x7fff47808f50));

    return 0;
}

但它显示错误。也许我使用了错误的语法,或者这可能不是这样做的。不管怎样,请告诉我正确的方法。

3 个答案:

答案 0 :(得分:2)

可以(以为不应该)将整数强制转换为如下指针:(void *) 0x7fff47808f50

转换具有实现定义和未定义的方面,但这意味着您的里程会有所不同。这个值显然会从编译器变为编译器,甚至可能是针对不同的编译,并且字节顺序可能与我们常规编写数字的方式不同,这意味着您可能需要修改一下才能使其正常工作。

这在实践中是可证明的,当实现定义的行为允许我们重现该行为时,以下内容将是合规的:

unsigned long long ptr_as_integer = (unsigned long long) "hello world";
printf("%s", (void *) ptr_as_integer);

int value = 42;
unsigned long long value_ptr_as_integer = (unsigned long long) &value;
printf("%d", * (int *) value_ptr_as_integer);

还有uintptr_t类型,专为此设计,但可选,因此无法保证存在...

好奇是好的;这就是我们学得最好的方法......但请不要在实践中使用它!你多久被教导不使用魔法数字?

答案 1 :(得分:1)

您可以使用char *为另一种类型的指针设置别名来读取单个字节:

int i;
char *p = (char *)ptr;
for (i=0; i<sizeof(*ptr); i++) {
    printf("p[%d]=%02hhx", i, p[i]);
}

答案 2 :(得分:1)

修改您的代码

#include<stdio.h>

int main(int argc, char** argv) {
    int num = 10;
    int *ptr;
    ptr = &num;

    //To output the address of the "num" variable
    printf("Address: %p\n", ptr);

    //Address is 0x7fff47808f50...

    //Using that address to print the data at variable "num"
    printf("Data: %d\n", *ptr);

    return 0;
 }

你问的答案是肯定的。

BUT:

  1. 您必须100%确定要使用的地址。例如,在任何类型的固件中,您总是将手册中定义的寄存器地址作为常规数字。我们像这样使用它们

    #define MY_REG_ADDR 0x12345ABC
    int a = *((int*)(MY_REG_ADDR))
    
  2. 现代操作系统确实解决了随机化问题,因此每次运行应用程序时都会更改可执行文件的虚拟地址sapce,因此您不能只使用硬编码地址。

  3. 这是我运行应用程序4次后的输出(修改后的代码)

    地址:0x7ffc279af5ac
    数据:10
    地址:0x7ffc2d78021c
    数据:10
    地址:0x7fffb36ae32c
    数据:10
    地址:0x7ffca2c2a9ec
    数据:10

    1. 您更改代码内存布局的每个时间都可能会发生变化,因此变量的地址也可能会发生变化