
扫描二维码
获取更多精彩
嵌入式杂牌军

编辑|追梦星空
公众号|嵌入式杂牌军
对知识的认知来说,很多时候感觉是不可靠的,你需要不断的去求证,这既可以深入,也可以避免“想当然”的错误!
文 章 导 读
今天给小伙伴们汇总下编程过程中经常出现的总线错误和段错误相关的内容!
阅读过程中有什么问题可以后台交流哈,!
1 总线错误
1)引起总线错误的原因
① 总线错误基本上都是由于未对齐的读或写引起的。
② 访问一块物理上不存在的内存引起。
2)这种错误为什么称为总线错误
出现未对齐的内存访问请求时,被堵塞的组件通常就是地址总线,所以称其为总线错误。
3)什么是对齐(alignment)
数据项只能存储在地址是数据项大小的整数倍的内存位置上。
n字节对齐,地址只允许是n的整数倍。
4)为什数据需要对齐
与任意的对齐有关的额外逻辑会使整个内存系统更大,运行更慢。
通过迫使每个内存访问局限在一个Cache行或一个单独的页面内,可以极大地简化并加速如Cache控制器和内存管理单元这样的硬件。
通常说的“数据项不能跨越页面或Cache边界”其实质就是数据对齐问题。
页和Cache的大小是经过精心设计的,只要遵守对齐规则就可以保证一个原子数据项不会跨越一个页或Cache块的边界。
5)解决总线错误的思路
解决总线错误的思路要从引起总线错误的原因出发。
bus error(core dumped) 总线错误(信息已转储)
出现上面的总线错误的提示后,可以排查一下有没有访问不存在的物理内存,数据有没有对齐的问题。
如果未初始化的指针恰好具有未对齐的值(对于指针所要访问的数据而言),它将会产生总线错误,而不是段错误。
对于绝大多数架构的计算机而言确实如此,因为CPU先看到地址,然后再把它发送给MMU。
注意:类型转换是可能引起总线错误的,比如char指针转为int指针时是可能出现总线错误的。
2 段错误
1)段错误产生的原因
段错误是指程序尝试访问一段不可访问的内存。
如果指针引用一个并不位于你的地址空间中的地址,操作系统便会对此进行干涉。
下面的程序会引起段错误:
int *p=0;
*p = 1; //引起一个段错误
段错误的报错通常如下:
segmentation fault(core dumped) 段错误(信息已转储)
segment fault
导致指针具有非法的值通常是由于不同的编程错误所引起的,和总线错误不同,段错误更像是一个间接的症状而不是引起错误的原因。
你的程序如果进行了修改(如在调试状态下编译或增加额外的调试语句),内存的内容便很容易改变,于是这个问题被转移到别处或干脆消失。
段错误是非常难于解决的,而且只有非常顽固的段错误才会一直存在。
2)导致段错误的几个直接原因
① 解除引用一个包含非法值的指针。
② 解除引用一个空指针(常常由于从系统程序中返回空指针,并未经检查就使用)。
③ 在未得到正确的权限时进行访问。例如,试图往一个只读的文本段存储值就会引起段错误。
④ 用完了堆栈或堆空间(虚拟内存虽然巨大但并不是无限的)。
3)可能导致段错误的常见编程错误
① 坏指针值错误。
在指针赋值之前就用它来引用内存,或者向库函数传送一个坏指针。
不要上当!如果调试器显示系统程序中出现了段错误,并不是因为系统程序引起了段错误,问题很可能还在存在于自己的代码中。
还有一种可能导致坏指针的原因是对指针进行释放之后再访问它的内容。
可以修改free语句,在指针释放之后再将它置为空值。
free(p);
p = NULL;
这样,如果在指针释放之后继续使用该指针,至少程序能在终止之前进行信息转储。
② 改写(overwrite)错误。
1> 越过数组边界写入数据。
2> 在动态分配的内存两端之外写入数据。
3> 改写一些堆管理数据结构。
③ 指针释放引起的错误。
1> 释放同一个内存块两次。
2> 释放一块未曾使用malloc分配的内存。
3> 释放仍在使用中的内存
4> 释放一个无效的指针。
一个极为常见的与释放内存有关的错误就是在for(p=start;p;p=p->next)这样的循环中迭代一个链表,并在循环体内使用free(p)语句,即试图多次释放同一个指针。
这样,在下一次循环迭代时,程序就会对已经释放的指针进行解除引用操作,从而导致不可预料的结果。
总结:在绝大多数架构的绝大多数情况下,总线错误意味着CPU对进程/任务引用内存的一些做法不满,而段错误则是MMU对进程/任务引用内存的一些情况发出抱怨。
今天就到这吧,希望对小伙伴有所帮助哈,喜欢的话欢迎转发、点赞、分享、在看、转载哈,。
免责声明:本文内容源于网络或技术手册,版权归原作者所有。如涉及侵权问题,请与我联系删除。
欢迎关注我的公众号,一起玩技术,撸代码!