有什么方法可以取消引用C中的内存地址?

时间:2019-01-31 09:34:37

标签: c

我了解C语言中指针的工作原理。指针基本上存储了存储器(say addr1)的地址,对指针的取消引用为我们提供了存储在该存储器地址addr1上的值。有什么方法可以直接取消引用内存地址addr1来获取存储在该位置的值?

我知道如何使用指针。我只想知道实际发生的情况。我试图使用内存地址在下面的代码中创建指针如何工作的相同场景。尽管我一直坚持从指针获取值。通过这个示例,我想知道指针的取消引用是如何工作的。

例如:

#define LOCATION 0x68feac //Assuming that the memory location is available

int main()
{
    int a = 10;
    *(int *)LOCATION = (int)&a;
    printf("%x\n", (*(int*)(LOCATION)));    //It gives me the address of a
    printf("%x\n", *((*(int*)(LOCATION)))); /* I thought it would de-refer but
                                                it gives me compile time error 
                                                "invalid type argument of unary 
                                                '*'" */

}

我尝试使用

如何取消引用LOCATION,以便我们获得价值10?任何想法或建议都会有所帮助。

4 个答案:

答案 0 :(得分:2)

您要的是:

printf("%x\n", *((int *)(*(int*)(LOCATION))));

因为在取消引用之前,需要将从*(int*)(LOCATION)检索到的int值转换为指针。

但是您真的不这样做!这是一种丑陋的语法,C编译器在优化无用变量方面非常出色。因此,请帮自己一个忙,并命名中介指针:

#define LOCATION 0x68feac //Assuming that the memory location is available

int main()
{
    int a = 10;
    int **loc = (int **)LOCATION;  // BEWARE only make sense in very special use cases!
    *loc = &a;
    printf("%p\n", *loc);    //It gives me the address of a
    printf("%x\n", **loc);
    return 0;
}

无论如何,在C语言中很少使用任意内存位置,因为编译器(和链接器)将使用您几乎猜不到的地址。我知道的唯一用例是访问嵌入式系统或内核模块中众所周知的物理地址

答案 1 :(得分:1)

在所有嵌入式uC开发中都很常见(请不要忘记volatile关键字)。

*(volatile int *)LOCATION = a;

以及如何打印

printf("a is : %d\n, *(volatile int *)LOCATION); 

或者如果您想存储a的地址

*(volatile int **)LOCATION = &a;

以及如何打印

printf("Address if a is : %p, a is: %d\n, (void *)*(volatile int **)LOCATION, **(volatile int **)LOCATION); 

现实生活中的例子:

#define GPIOA_BASE 0x40000000

#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)

{
  __IO uint32_t MODER;        /*!< GPIO port mode register,                                  Address offset: 0x00 */
  __IO uint16_t OTYPER;       /*!< GPIO port output type register,                           Address offset: 0x04 */
  uint16_t RESERVED0;         /*!< Reserved,                                                                 0x06 */
  __IO uint32_t OSPEEDR;      /*!< GPIO port output speed register,                          Address offset: 0x08 */
  __IO uint32_t PUPDR;        /*!< GPIO port pull-up/pull-down register,                     Address offset: 0x0C */
  __IO uint16_t IDR;          /*!< GPIO port input data register,                            Address offset: 0x10 */
  uint16_t RESERVED1;         /*!< Reserved,                                                                 0x12 */
  __IO uint16_t ODR;          /*!< GPIO port output data register,                           Address offset: 0x14 */
  uint16_t RESERVED2;         /*!< Reserved,                                                                 0x16 */
  __IO uint32_t BSRR;         /*!< GPIO port bit set/reset registerBSRR,                     Address offset: 0x18 */
  __IO uint32_t LCKR;         /*!< GPIO port configuration lock register,                    Address offset: 0x1C */
  __IO uint32_t AFR[2];       /*!< GPIO alternate function low register,                Address offset: 0x20-0x24 */
  __IO uint16_t BRR;          /*!< GPIO bit reset register,                                  Address offset: 0x28 */
  uint16_t RESERVED3;         /*!< Reserved,                                                                 0x2A */
}GPIO_TypeDef;

和用法:

GPIOA -> MODER = value; 

__IO被定义为volatile

#define __IO volatile

答案 2 :(得分:-1)

要从给定位置取消引用int:

int val = *((int*) LOCATION);

((int*) LOCATION)为您提供了将LOCATION强制转换为int指针的方法,因此最后一步是取消引用它。

示例(将精确的LOCATION指定为现有的整数指针,但其工作原理相同)

#include <stdio.h>

#define LOCATION ((void*) &a)

int main(void){
    int a = 123;
    printf("a=%d, &a=%p\n", a, &a);

    printf("*LOCATION=%d, LOCATION=%p\n", *((int*) LOCATION), LOCATION);
}

答案 3 :(得分:-2)

您基本上可以正确执行操作,但是指针不仅是另一个整数,而且不能使用任意值,必须使用分配给程序的值(即由OS给定的值)。

  1. 为了能够取消引用指针,我们将值的类型存储在内存中。这意味着您应该声明int *LOCATION;而不是定义,以声明要指向存储整数的存储位置。

  2. 因此,您不应该转换指向int的指针,因为&a已经具有相同的类型:指向int的指针。

    此外,您无法为define的值分配值。定义不是类型-我确定您会找到另一个关于它到底是什么的问题。

  3. 在取消引用之前获取a的地址是正确的,因此请勿提前为LOCATION分配任意值。最好将其分配为NULL,以表示指针未初始化。

您的代码将变为:

int* LOCATION = NULL;
int main()
{
    int a = 10;
    LOCATION = &a;
    printf("address of a: %lx\n", LOCATION);    // accessing the pointer accesses the memory address
    printf("value of a: %x\n", *LOCATION); // dereferencing the pointer with * gives the value stored at that address
} 

现在,如果您使用的是内存映射外设,例如@P__J__建议使用固定地址的某些硬件寄存器,则需要将地址转换为正确的类型。

#define LOCATION_ADDR 0x68feac
int volatile * const LOCATION = (int *) LOCATION_ADDR; 
  • volatile在这里意味着存储在该位置的内存可能会由于程序外部因素而改变。这会更改编译器的优化,例如,一个循环读取该位置,直到它被更改而不会被永久删除为止。
  • const表示指针位置不会改变,尽管它包含的数据可能会有所变化(与const int有所不同!)。
  • 一旦对此感到满意,可以直接在定义中使用它,即#define LOCATION ((volatile int*)0x68feac)

如果您希望硬件寄存器包含一个指向int的指针,只需添加另一个*

#define LOCATION 0x68feac //Assuming that the memory location is available

int main()
{
    int a = 10;
    // dereferencing the address at LOCATION, storing into it the address of a
    *((volatile int **)LOCATION) = &a;
    printf("%p\n", *((volatile int **)LOCATION));
    printf("%x\n", **((volatile int **)LOCATION));
    return 0;
}