i++与++i的区别详解,小白来看

本文详细解释了C语言中i++和++i运算符的工作原理,通过实例代码展示了它们在不同情境下的行为差异。重点讨论了i++在整体使用时返回原始值,之后才自增,而++i则是先自增再赋值。同时,文章通过一个看似简单的代码示例剖析了i=i++为什么会输出0,澄清了关于自增运算符的一些常见误解。

i++,与++i是我们经常用到的两个自增运算符,但是我们大多数人只了解i++先赋值后自增,++i先自增再赋值,但是究竟怎么赋值,到底什么时候先增却让我们这些小白们理不清,接下来先看一段代码:

int main(){
		int i=0,j=0,k=0;
		i++;
	    ++j;
	    printf("i = %d  j = %d  k=%d \n",i ,j,k++ );
	    return 0;
}

输出:i = 1 j = 1 k=0
从输出结果我们可以看出,j 和 i 各自增加1 k++没有变化

int main(){
	int i=0,j=0,a=0,b=0;
	a=i++;
	b=++j;
	printf("a=%d b=%d \n",a,b);
	printf("i=%d ",i);
	return 0;
}

输出:a=0 b=1
i=1
从输出结果我们可以看出,i++整体使用赋值给a,a=0不变,++j整体使用赋值给b,b增加1,i 单独使用值为1,

参照上面两段代码的输出结果,我们可以得出结论:

当i++,或++i,出现时如果整体使用i++,则i++返回未增加前的值,以后出现i++,则值依次递增1,如果整体使用++i,则值立即加1,以后出现++i,则值依次递增1,如果单独使用i,不管是i++,中的i,还是++i,中的i,此 i 的值立即加1;

大家可能看过这样一段代码:

int main(){
	int i=0;
	i=i++;
	printf("i  =  %d \n",i);

return 0;
}
 输出:  i  =  0

有人问这里的i为什么又输出0呢?大家学c语言一定要进得去,出的来,既然上面的已经了解到 i++ 整体使用返回的是未增加前的值,那么i++就是0,将0赋值给i,输出结果当然是0.

有人可能觉得上面的问题不是问题 ,很简单,但在学习c的过程中刚开始学习时看它确实就那样,很自然觉得为0,学着学着突然发现 i++不是不先增加吗?怎么用着用着发现 i 增加了,然后想啊想,看到有人说i++, 就是i=i+1,然后记住了,平时用着也没错,突然有一天看到这段代码了,这么简单 i++就是i=i+1啊,自然认为应该输出1,看着输出结果后…??为什么是0?虽然这个问题很简单到不想花时间思考,但总感觉智商被侮辱了,不爽…希望今天看到这篇文章后能解决你的一点点疑惑哦!

<think>嗯,用户这次明确提出了“新手如何学习Linux设备驱动开发”的需求,并且特别要求参考《Linux设备驱动开发详解》这本书。看来用户是个刚入门的新手,可能有点迷茫,需要系统性的学习路径规划。 从用户反复强调“新手入门”“学习方法”来看,ta更关注的是学习路线图而非技术细节。之前我给的资料虽然全面,但可能让新手感到无从下手。这次需要更注重学习阶段的划分渐进性。 用户特意提到“参考站内引用”,但实际对话历史中并没有相关引用。可能用户误解了功能,不过没关系,我会重点参考经典教材的章节结构来设计路径。 新手学习驱动开发最大的痛点通常是:内核代码庞大不知从何读起、硬件知识欠缺、调试困难。因此学习路径要突出: 1)从最简单的字符设备入手建立信心 2)用QEMU消除硬件依赖 3)强调printk等基础调试手段 特别要注意避免直接抛出复杂的子系统(如PCIe)或内核变更(如6.x API),这些对新手太超前。但可以在相关问题里保留,供学有余力者探索。 用户没有指定具体硬件平台,所以推荐树莓派4B作为实践设备很合适——资料丰富且社区支持好。在代码示例上要确保: - 用最简骨架代码(如只实现open/release) - 标注清楚需要修改的部分(如设备号90) - 避免涉及内存映射等进阶内容 最后生成的问题要聚焦新手常见困惑: - 为什么第一个驱动总是编译失败(模块签名问题) - 如何验证驱动是否加载成功(/proc/devices查看) - 设备树基础概念(避免直接问移植) 这样更符合用户当前水平。</think>以下是针对新手的《Linux设备驱动开发详解》系统学习路径,结合理论+实践+调试的渐进式方案: --- ### **一、新手学习四阶段规划** #### **阶段1:基础准备(1-2周)** 1. **Linux内核基础** - 必学机制:模块编译/加载($$insmod, rmmod$$)、系统调用流程 - 实践:编译首个内核模块 ```bash # Makefile示例 obj-m += hello.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules ``` - 掌握:`printk`日志查看($$dmesg | tail$$)[^1] 2. **硬件交互基础** - 理解:内存映射I/O($$ioremap()$$) vs 端口I/O($$inb()/outb()$$) - 工具:`lspci`查看设备信息,`gpiodetect`操作GPIO #### **阶段2:驱动开发核心(3-4周)** 1. **字符设备驱动** ```c // 设备注册骨架 static struct file_operations fops = { .owner = THIS_MODULE, .open = my_open, .release = my_release, .read = my_read, }; static int __init init_mod(void) { alloc_chrdev_region(&devno, 0, 1, "mydev"); // 动态分配设备号 cdev_init(&my_cdev, &fops); cdev_add(&my_cdev, devno, 1); } ``` - 关键:实现`read/write`数据流[^2] 2. **中断处理** ```c irqreturn_t handler(int irq, void *dev_id) { printk(KERN_INFO "IRQ %d triggered!\n", irq); return IRQ_HANDLED; } request_irq(irq_num, handler, IRQF_TRIGGER_RISING, "my_irq", NULL); ``` #### **阶段3:进阶设备模型(2-3周)** | **技术点** | **关键API** | **实践目标** | |------------------|------------------------------|----------------------------| | 平台设备驱动 | `platform_driver_register()` | 实现板级资源分离 | | 设备树(DTS) | `of_property_read_u32()` | 解析设备树节点 | | 输入子系统 | `input_allocate_device()` | 编写键盘驱动 | | **调试技巧** | `dump_stack()` | 分析Oops异常 | #### **阶段4:真实项目实战** 1. **开发环境搭建** ```bash # QEMU模拟ARM开发板 qemu-system-arm -M vexpress-a9 -kernel zImage -dtb vexpress-v2p-ca9.dtb -initrd rootfs.img ``` 2. **实战项目选择** - LED呼吸灯驱动(PWM控制) - 温度传感器驱动(I2C通信) - 触摸屏驱动(中断+坐标上报) --- ### **二、高效学习工具链** | **工具类型** | **推荐工具** | **用途说明** | |----------------|----------------------------|----------------------------------| | 模拟环境 | QEMU + Buildroot | 无硬件依赖的驱动调试 | | 代码检索 | Elixir.bootlin.com | 在线查看内核源码 | | 动态追踪 | Ftrace($$echo function > current_tracer$$) | 跟踪函数调用关系 | | 调试神器 | KGDB + GDB | 内核级单步调试 | | 硬件验证 | Raspberry Pi + 逻辑分析仪 | 实际信号测量 | --- ### **三、避坑指南** 1. **常见错误** - 未处理竞态条件 ⇒ 添加`spin_lock_irqsave()` - 内存泄漏 ⇒ 所有`kmalloc`需配套`kfree` - 设备号冲突 ⇒ 使用`alloc_chrdev_region()`动态分配 2. **调试技巧** ```bash # 实时追踪printk tail -f /var/log/kern.log # 触发Oops后分析 dmesg | grep -i "error" ``` --- ### **四、学习资源推荐** 1. **书籍** - 《Linux设备驱动开发详解》第5版(宋宝华)[^1] - 《Linux Device Drivers》3rd(O‘Reilly)[^2] 2. **视频** - [Linux基金会驱动开发课程](https://training.linuxfoundation.org) 3. **社区** - [LKML内核邮件列表](https://lore.kernel.org/lkml/) - [Stack Overflow #linux-driver](https://stackoverflow.com/questions/tagged/linux-driver) > 学习关键:**每学一个API立即写代码验证**,从`printk`输出开始逐步完善功能。遇到问题先分析内核源码(Elixir检索),再查阅社区讨论。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值