【问题标题】:Why typecast a pointer at its declaration?为什么要在其声明中对指针进行类型转换?
【发布时间】:2020-06-24 15:16:58
【问题描述】:

不确定我是否正确地表达了这个问题,也不确定如何最好地解释我试图回答的内容,所以请耐心等待。

当定义一个微控制器寄存器时,你会这样写:

#define io_register (*(volatile unsigned char *)0x25)

我在这里也找到了这行代码:Pass a hex address to a Pointer Variable

int *pointer = (int *) 0x00010010;

我知道指向 int 的指针被声明在 = 符号的左侧,但是为什么在它的右侧有一个类型转换 *(int )

#define 相同,我知道 0x25 处的值正在被取消引用,但为什么我不能这样写:

#define io_register *(0x25)

int *pointer = 0x25;

我在这里缺少什么?请随时改写或更正我所犯的任何错误,但我仍在努力解决指针和寄存器问题。

【问题讨论】:

  • 告诉我你能做到吗:- float var = "abc";?
  • @Lucas 是的,你可以。
  • @Lucas 它将在浮动中存储对字符串文字的引用。如果你施放float var = (float)"abc";,你会抑制警告。
  • 我亲爱的兄弟@P__J__ ,在将这个表达式写入我的代码后,我不会得到 warning,我会收到一条错误消息,指出 error: incompatible types when initializing type 'float' with type 'char *' .
  • @P__J__ 即使我对字符串文字进行了类型转换。类型转换后我们会得到error: pointer value used where a floating point value was expected 所以,告诉我你在说什么“它将把对字符串文字的引用存储在浮点数中。”

标签: c pointers embedded


【解决方案1】:

任何赋值操作的一个重要前提是数据类型兼容性。换句话说,方程的 (int *pointer = 0x25;) LHS (int *pointer) 的数据类型必须与方程的 RHS (0x25) 的评估结果的任何数据类型兼容。

例如,如果LHSRHS都是int类型,那么分配右轴到左轴。

但是,在这个表达式中:

int *pointer = 0x25;

LHS 中有 int * 数据类型,RHS 中有 int 数据类型。因此,LHS 和 RHS 之间存在不兼容性。这就是为什么您需要将 RHS 转换为 (int *)

【讨论】:

  • 不能。应该。编译器会询问(使用警告):dude! Are you sure?。当你明确地投你回答Yes I am, my compiler friend
  • 对不起。我没有得到你。 @P__J__
  • 如果你是关于这个 exp。 int *pointer = 0x25。那么你知道,每个人都知道我们不能手动为指针提供内存地址。
  • @P__J__ 这个答案是正确的。编译器也可以给出错误作为警告,只要它给出某种诊断方式。这样做的原因不是“你确定”,而是“这是无效的 C,你想要一个非标准的扩展吗?”详情见:stackoverflow.com/questions/52186834/…
【解决方案2】:

演员表抑制了警告。这就是它在这些声明中的作用。否则会被强制转换为隐式方式,并省略警告。代码或程序执行没有区别。


#define io_register *(0x25)

*(0x25) 在任何情况下都不是指针,io_register 在使用时意味着:乘以 0x25。

int x = 10 io_register;

表示:int x = 10 *(0x25);

【讨论】:

  • 只是为了澄清一点,0x25 可以写成 C 中的 int 值吗? IE。二进制十六进制等?我可以对包含十六进制或二进制值的整数执行位移等操作吗?
  • 0x25 它是整数常量,它是一个整数值。 16、0x10、020 0b10000 之间没有区别(0b 是 gcc 扩展)。
  • int * pointer = 0x25; 是无效的 C,它违反了约束。编译器必须生成诊断消息。不应该发生任何“隐含”的事情,那就是不符合/非标准的扩展。
  • 这只是警告与错误的常见问题,以及应该阻止代码生成二进制文件的内容 - 这些事情超出了 C 语言的范围。如果您使用-pedantic-errors,gcc 和 clang 等流行的编译器会阻止无效 C 的编译。如果您不这样做,他们只会发出警告并生成不合格的二进制文件。如果你只是用默认编译,比如gnu11,那么你得到的是gnu11,而不是c11。
  • 嵌入式系统编译器可能更宽松,尽管我发现一个不允许这样做的记录只是为了记录。 Codewarrior 给出“错误:类型不匹配(预期为 int*,给定 int)”。这是完全符合的行为。
【解决方案3】:

int *pointer = (int *) 0x00010010;

你告诉指针指向内存中的一个绝对地址,那个地址的值可以用*pointer解引用。

int *pointer = 0x25;

编译器不喜欢这样,因为 0x25 是一个整数,但指针不是整数,它是一个整数指针。

【讨论】:

    【解决方案4】:

    需要强制转换,因为0x00010010 不是指针而是整数(它是intunsigned intlong int 中第一个可以表示值65552 的类型)。

    只有具有 0 值的整数常量表达式才能被隐式转换为指针(即没有强制转换);结果指针将是一个空指针。


    你自然会写

    #define io_register *(0x25)
    

    但您不能使用 io_register 访问地址 0x25 处的内存,因为 0x25 不是指针 - 它是整数。

    在 C 中,并不真正访问地址;取而代之的是取消引用指针以获取指定对象lvalues,然后获取该对象的值,或者为其设置一个新值。

    【讨论】:

    • 你当然可以使用它,例如int x = 5 io_register;io_register表示“乘以0x25
    猜你喜欢
    • 2012-04-05
    • 1970-01-01
    • 2013-06-05
    • 2021-05-08
    • 2017-10-06
    • 2022-11-30
    • 2014-12-01
    • 2020-07-30
    • 1970-01-01
    相关资源
    最近更新 更多