c语言将指针转换为整形,关于嵌入式:为什么我们将整数值转换为C语言中的指针类型...

本问题已经有最佳答案,请猛点这里访问。

我试图找到答案,但是没有。 假设我想在内存中的某个特定地址写入一个值。 假设我要在地址0x80005000上写7。

所以我做这样的事情:

uint32_t *ptr = (uint32_t* )0x80005000;

*ptr = 7;

我不明白的是为什么我们需要将地址的十六进制值转换为指针类型。 如果不进行转换,那会出什么问题?

您是否在问为什么不是uint32_t *ptr = 0x80005000;(没有显式强制转换)? 还是为什么它不是uint32_t ptr = (uint32_t)0x80005000;(没有指针)?

您如何在不向编译器指示它是地址的情况下在特定地址写入值? 强制转换用于指示这一点。

我问为什么不是uint32_t * ptr = 0x80005000; 为什么我们需要那里的演员。 @ P.W,但是我们可以将十六进制值分配给指针,而不必将其强制转换为指针。 我刚刚检查。

@ Cantaff0rd不,您不能在兼容的C编译器上执行此操作。 例如在标准模式下尝试使用gcc,gcc -std=c11 -pedantic-errors,您会发现它不会让代码通过。 请参阅上面的链接以获取解释。

好吧会谢谢

强制转换基本上是一种告诉编译器"是的,我确定我在做什么,我将对任何后果负责"。

在您的特定情况下,进行强制类型转换的主要原因是使编译器安静,以使其不发出警告。该代码将进行编译(除非您使用参数-pedantic-errors进行编译),并且在没有强制转换的情况下也不太可能正常工作。

但是,请记住,没有强制转换,您将调用未定义的行为。 C11标准6.5.16.1说:

One of the following shall hold:112)

the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;

the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;

the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or

the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.

这两个胖点在这里是相关的,没有铸就就无法实现。

在评论中引用伦丁的话:

For example given unsigned* ptr = NULL; ... ptr = 0x12345678; foo = *ptr; might in theory lead to the compiler accessing address NULL. Because during optimization the compiler is free to assume that ptr was never assigned a value, since no valid form of pointer assignment is present in the code.

但在另一些情况下,使用铸造进行欺骗。一个经典的例子是原始Doom引擎中使用的Carmack技巧。这是带有原始注释的代码:

float Q_rsqrt( float number )

{

long i;

float x2, y;

const float threehalfs = 1.5F;

x2 = number * 0.5F;

y  = number;

i  = * ( long * ) &y;                       // evil floating point bit level hacking

i  = 0x5f3759df - ( i >> 1 );               // what the fuck?

y  = * ( float * ) &i;

y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration

//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

return y;

}

注意:以上代码会导致未定义的行为,因此不应视为优质C代码的示例。

同样,有些人即使不应该使用强制转换也可以使编译器安静。请记住,让编译器安静总是有风险的。这是一个如何出错的示例:

int main()

{

char c = 'h';

float a = 0.123;

printf("%c %f

", c, a);

int *cp = (int *) &c;

*cp = 'h';

double *ap = (double*) &a;

*ap = 0.123;

printf("%c %f

", c, a);

}

和输出。这两行"应该"相同。

$ ./a.out

h 0.123000

? -0.000000

铸造是非常危险的事情。在演员表前务必三思。

那句话总结了我对那条线的理解

"没有强制转换,代码可以编译并正常工作"不,C语言没有定义它,如果不使用强制转换会发生什么。同样,您链接的该垃圾代码会出于其他原因调用UB,包括严格的别名,以及带符号整数的隐含定义的右移。不应使用或研究它。评论不言自明。

例如,给定的unsigned* ptr = NULL; ... ptr = 0x12345678; foo = *ptr;在理论上可能导致编译器访问地址NULL。因为在优化过程中,编译器可以自由地假定从未为ptr分配任何值,因为代码中没有有效的指针分配形式。

@Lundin谢谢。我解决了这些问题。

不要引用我,而是引用C标准。 C17 6.5.16.1。反过来,这仅表示这是一个约束违例,因此可能发生任何事情。

@Lundin我将添加。但是,如果您满意,我想保留您的报价。它解释得很好。

但是,引言主要是关于UB如何表现自己的推测,这并不是很有意义。重要的是要知道它是UB。

@Lundin它是您的报价,所以您说了算。如果您愿意,我可以删除完整的报价单或仅删除您的名字,但我确实认为它可以增加价值。

无论如何,这显然是我链接的帖子的完全相同。我本来会投近票的,但是我偏偏,所以...

@Lundin ...所以你丢下了我无法忽视的暗示? :D近距离投票。

0x80005000的类型(可能是)int,它不是指针,并且不能在不进行强制转换的情况下分配给指针类型的变量(从技术上讲可以,但是编译器应该抱怨它)。

强制转换值告诉编译器"该值的类型实际上与您认为的不同,因此可以"。

我明白那个。但是,如果我们不强制转换并忽略编译器警告,将会发生什么。给我举一个可能发生的坏事的例子

@ Cantaff0rd可能不会发生任何不良情况,或者可能无法正常工作。它实际上取决于太多因素,您应该将所有警告都视为错误,并且永远不要忽略它们,从长远来看,这将使您作为C程序员的生活变得更加轻松。

您的老板可能会因您签入破坏编译器警告而破坏构建的代码而解雇您。编程中的坏事并不仅限于CPU。

@ Cantaff0rd C标准仅表示,在违反C语言的情况下,例如这种情况,编译器必须提供"诊断消息"。错误和警告不是该标准定义的术语。因此,就标准而言,如果C编译器向您发出警告就足够了。如果尝试仍然运行程序,则它是依靠非标准扩展或未定义的行为。

行。谢谢大家的回答!

在具有32位int的常规系统上,0x80005000不会具有类型int,因为它大于INT_MAX

@ M.M实际上是unsigned int,因为十六进制整数常量的特殊规则。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值