深刻理解C语言中的*和&、类型转换

本文通过几个具体的C语言代码示例,探讨了整数与浮点数之间的类型转换,以及指针操作的细节。包括如何使用指针转换整数到浮点数,并解释了这种转换背后的原因。

前两天同学问我一道面试题,如下:

int a=1;
printf("%f",a);


结果输出是0.00000,好像这是和编译器有关系的,我试验在codeblock上,亲测printf("%f",int)都会是0。

后来又试了试别的代码:

#include <cstdio>
#include <iostream>
using namespace std;

int main()
{
    int a=0x43300000;
    float b=*(float *) &a;
    float c=(float)a;
    cout << (float*) &a << endl;       //1
    printf("%f\n",b);        //2
    printf("%f\n",c);        //3
    return 0;
}

这样会输出什么呢?看下图


具体解释:

1指的是先取a的地址,也就是0x6afef4,此时&a就可以看成一个指针*p,p==0x6afef4,不过指向的是int型的,然后(float*)p代表将p指向的地址变为float型,输出的时候还是个float型指针,所以是地址。

2指的是取1中说的float型的指针的内容,但本来是int型的数,按照float型的数来读取就不一样了,因为float型内存中是分为三部分的,符号位、指数位、尾数,具体可以搜一下float内存表示,推荐博客http://blog.youkuaiyun.com/nethibernate/article/details/6120382。

3指的是将a中的数据直接类型转换,这时他的数不会变,所以和2不一样。


PS:对*和&的理解

void f(int * a)   // a 是一个int型的指针,a指的地址存放的是int型的数据
{
  a    // 取指针a的值(即地址)
  *a   // 取指针a指向的内容
  &a   // 取存放指针a的值的地址
}


如果a是一个数组

&a+1 = a + 1*sizeof(a);    //如果数组a有100个数据,哪就移动100*sizeof(a[0])
a+1 = a +1*sizeof(a[0]);    //仅移动sizeof(a[0])


&lt;think&gt;嗯,用户问的是C语言中int ch转字符(uint_8 *)&amp;ch的原理。首先我得理清楚这个问题到底在问什么。用户可能是在处理类型转换或者指针操作时遇到了问题,想了解这种转换的具体机制。 首先,int ch声明了一个整型变量ch,而(uint_8 *)&amp;ch则是取ch的地址,并将其转换为指向uint_8类型的指针。这里的uint_8应该是指无符号8位整数,也就是unsigned char。所以问题应该是关于如何将int变量的地址强制转换为指向无符号字符的指针,以及这种转换的原理可能的应用场景。 接下来,我需要考虑intuint_8的大小差异。int通常是4字节,而uint_8是1字节。所以当用(uint_8 *)&amp;ch时,实际上是将一个指向4字节整型的指针转换为指向1字节无符号整型的指针。这意味着通过这个指针只能访问int的第一个字节,具体是哪个字节取决于系统的字节序。比如,在小端系统中,第一个字节存储的是最低有效位,而在大端系统中则是最高有效位。 然后,用户可能想知道这样的转换有什么用途。常见的例子可能是处理二进制数据,比如网络传输或文件读写时,需要将数据按字节处理。通过这种指针转换,可以逐字节访问int的各个部分,进行序列化或反序列化操作。 但这里也存在潜在的问题。比如,直接通过uint_8指针修改数据可能会影响原int变量的值,尤其是当只修改其中一个字节时,可能导致不可预期的结果。此外,对齐填充问题也可能出现,虽然对于基本类型如int来说,这种情况较少,但在结构体中可能需要考虑。 另外,用户可能对指针的类型转换内存布局不太清楚,需要解释强制转换后的指针如何访问内存。比如,假设ch的地址是0x1000,转换为uint_8指针后,指向的地址还是0x1000,但解引用时只会读取或修改该地址的一个字节。 可能还需要提到类型别名的严格别名规则(strict aliasing),即通过不同类型的指针访问对象可能导致未定义行为,但uint_8(即unsigned char)在C中是例外,允许通过字符指针访问任何对象的内存表示。因此,这种转换在标准中是允许的,但需谨慎使用。 总结用户的需求,他们可能是在学习指针、类型转换,或者在处理底层数据时遇到了需要逐字节操作的情况。需要详细解释转换的原理、内存布局的影响、字节序的问题,以及使用时的注意事项,帮助他们正确理解应用这种技术。&lt;/think&gt;在C语言中,表达式 `(uint8_t *)&amp;ch` 的底层原理涉及指针类型转换内存访问方式,下面分步骤详解: --- ### **1. 变量定义与内存布局** 假设定义 `int ch = 0x41424344;`: - `int` 类型通常占4字节(具体取决于编译器平台)。 - `ch` 在内存中的存储方式取决于字节序(Endianness): - **大端序**:高位字节在前,内存布局为 `0x41 42 43 44`。 - **小端序**:低位字节在前,内存布局为 `0x44 43 42 41`。 --- ### **2. 取地址操作 `&amp;ch`** - `&amp;ch` 获取变量 `ch` 的 **起始内存地址**。 - 例如,假设 `ch` 的地址是 `0x1000`,则 `&amp;ch` 的类型是 `int *`。 --- ### **3. 强制类型转换 `(uint8_t *)`** - `(uint8_t *)&amp;ch` 将 `int *` 类型的指针强制转换为 `uint8_t *` 类型。 - **关键效果**: 1. 指针的 **目标类型** 从 `int` 变为 `uint8_t`(即单字节无符号整数)。 2. 通过这个指针访问内存时,每次 **仅操作1字节**(而非原来的4字节)。 --- ### **4. 访问单个字节** 通过 `uint8_t *` 指针访问内存时: - 解引用 `*((uint8_t *)&amp;ch)` 会读取 `ch` 的 **第一个字节**(具体值取决于字节序)。 - 例如: - 小端序下,`*((uint8_t *)&amp;ch)` 返回 `0x44`。 - 大端序下,返回 `0x41`。 --- ### **5. 遍历所有字节** 可以通过指针偏移访问 `int` 的所有字节: ```c uint8_t *p = (uint8_t *)&amp;ch; for (int i = 0; i &lt; sizeof(int); i++) { printf(&quot;Byte %d: 0x%02X\n&quot;, i, p[i]); } ``` --- ### **6. 典型应用场景** 1. **逐字节处理数据**(如网络协议、文件读写)。 2. **绕过严格别名规则**(Strict Aliasing Rule):C标准允许通过 `char *` 或 `unsigned char *` 访问任意对象的内存。 3. **内存操作**(如 `memcpy`、哈希计算)。 --- ### **7. 注意事项** 1. **字节序问题**:不同平台可能返回不同的字节顺序。 2. **对齐问题**:`int` 可能要求内存对齐,直接操作字节时需谨慎。 3. **可移植性**:依赖于 `int` 的大小字节序,跨平台代码需特殊处理。 4. **类型安全**:强制转换会绕过编译器类型检查,需确保操作合法。 --- ### **总结** `(uint8_t *)&amp;ch` 的本质是通过指针类型转换,将 `int` 的内存区域解释为单字节无符号整数数组。这种操作在底层编程中常见,但需要深刻理解内存布局字节序的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值