许可优化
许可优化
产品
产品
解决方案
解决方案
服务支持
服务支持
关于
关于
软件库
当前位置:服务支持 >  软件文章 >  2021/10/27 Paradigm学习笔记

2021/10/27 Paradigm学习笔记

阅读数 1
点赞 0
article_banner

1、C++函数重载原理

C++,调用函数时,根据不同的label来实现重载!
例如

int memcmp(void *p)
{
	int n = 17;
	int m = memcmp(&n)
}

如果是C,翻译成汇编语言:

CALL <memcmp>

如果是C++,翻译成汇编语言:

CALL <memcmp_void_p>

再如

int memcmp(void *v1, void *v2, int size)

如果是C,翻译成汇编语言:

CALL <memcmp>

如果是C++,翻译成汇编语言:

CALL <memcmp_void_p_void_p_int>

对于C++,入参的不一致 → “链接”错误→相比于C更安全,但也更死板!

2、 debug   error

  • segment fault 段错误 使用内存没有映射到“段”的地址导致的!在我们的“抽象内存模型”中,内存被分为“stack”、“heap”和“code”三段!NULL = 0,不在任何一个段内,如果对 NULL 进行 dereference,就会报 “segment fault”!
  • bus error 总线错误 硬件和操作系统对所有数据类型变量的地址进行了限制,int型变量的地址应该是4的倍数!使用指针时候,如果地址没对齐,会报“bus error”!
数据类型对齐
char1
short2
int4
其它4
void *vp =...
*(short *)vp = 7; // 50% → bus error
*(int *)vp = 7; // 75% → bus error
*(char *)vp = 7; // OK!!!

3、缓冲区溢出

缓冲区溢出(buffer overflow)是指下面这种情况:

int main()
{
	int i;
	int array[4];
	for(i = 0; i < 4; i++) {
		array[i] = 0;
	};
	return 0;
}

在这里插入图片描述

4、缓冲区溢出之大小尾不同

int main()
{
	int i;
	short array[4];
	for(i = 0; i <= 4; i++) {
		array[i] = 0;
	};
	return 0;
}

在这里插入图片描述

5、更有趣的“无限递归”错误

void foo()
{
	int array[4];
	int i;
	for(i = 0; i <= 4; i++) {
		array[i] -= 4;
	}
}

在这里插入图片描述

6、利用“内存结构”传递数据

void DeclearAndInitArray()
{
	int array[100];
	int i;
	for(i = 0; i < 100; i++) {
		array[i] = i;
	}
}
void PrintArray()
{
	int array[100];
	int i;
	for(i = 0; i < 100; i++) {
		printf("%d\r\n", array[i]);
	}
}
int main(int argc, char **argv)
{
	DeclearAndInitArray();
	PrintArray();
}

为什么没有进行函数之间的数据传递,仍然能够正确打印出来 0~99呢?

   答:调用DeclearAndInitArray(),活动记录中有408(4+100x4+1x4)个字节,数组占据了saved PC下面的400个字节,DeclearAndInitArray()函数RET后,虽然这存放数组的400个字节已经出栈,但是并没有被清0;

继续调用PrintArray(),它的活动记录将占用刚才DeclearAndInitArray()的位置,并且活动记录的结构与DeclearAndInitArray()一模一样,此时,直接打印数组中的数据,会成功打印出DeclearAndInitArray()留在内存中的0~99。

这个特性能用在哪里?答:中断服务函数中!

   留给中断服务函数处理事务的时间是很短的,我们可以先构造好一些常量数据,存放在“”中某个地方,这样在中断服务函数中就免于构造这些数据的麻烦了!

7、为什么入参要从右向左压栈?

为了实现“可变参数”…

   通常有“可变参数”的 编程语言 ,函数入参都是从右向左压栈!

int printf(const char *control, ...);

…是可变参数!可以是任何类型数据,并且“个数”不限!

printf("%d + %d = %d \r\n", 4, 4, 8);

在这里插入图片描述

8、为什么复合数据类型数据要从先到后压栈?

struct type {
	int code;
};
struct type_one {
	int code;
	...
};

从上到下压栈,可以得到code与结构体变量基地址的距离!反着来,得到这个“距离”就依赖于总长度了,会变得复杂!!!

比如咱们的网络IP地址,以前的网络地址是IPv4的,用4个字节表示IP地址,某天大家意识到,4个字节的IP地址会很快被用光,因此开发了6个字节的IP地址。IPv4和IPv6对应着不同的结构体,我们希望IPv6能够兼容IPv4,所以IPv6的前4个字节结构与IPv4是一样的!要是IPv6的前4个字节后入栈,很难得到其余结构体变量基地址的距离了,会给变成带来麻烦!

9、什么是虚拟地址空间?

10、模拟“单一航班出售150张票”

int main()
{
	int numAgents = 10;
	int numTickets = 150;
	for(int agent = 1; agent <= numAgents; agent++) {
		SellTickets(agent, numTickets / numAgets);
	}
	return 0;
}
void SellTickets(int agentID, int numTickestoSell)
{
	while(numTickestoSell > 0) {
		printf("Agent %d sells a ticket \r\n", agentID);
		numTickestoSell--;
	}
	printf("Agent %d: All down.\r\n", agentID);
}

预期结果:

   打印出来160行;其中 Agent %d: All down.\r\n 占用10行。

上面这样实现,每个agent会依次买票,并不会10个 agents  同时一起买票!

希望使用1个“线程”包。

int main()
{
	int numAgents = 10;
	int numTickets = 150;
	InitThreadPackage(false);
	for(int agent = 1; agent <= numAgents; agent++) {
		char name[32];
		sprintf(name, "Agent %s Thread", agent);
		ThreadNew(name, SellTickets, 2, agent, numTickets / numAgets); // 把狗狗们都放到起跑线上
		RunAllThreads(); // 把门打开,大家一起跑啊!
	return 0;
}
void SellTickets(int agentID, int numTickestoSell)
{
	while(numTickestoSell > 0) {
		printf("Agent %d sells a ticket \r\n", agentID);
		numTickestoSell--;
		if(RandomChance(0.1)) {
		// 模拟条件:10% 概率被强制暂停运行
			ThreadSleep(1000);
		}
	}
	printf("Agent %d: All down.\r\n", agentID);
}

paradigm 关键词总结:

适用于单片机程序设计的一套paradigm体系


Part 1 C基础(功能实现)

  • C的数据类型及其位模式

        – 原子类型:char、short、int、long、float、double、void *

        – 复合类型:array、string、struct、union

        – 特殊类型:bool、sfr、sfr16、sbit
  • 算法与数据结构

        – 筑基_C_1 判断大小端模式

        – 筑基_C_2 打印数据的位模式

        – 筑基_C_3 交换两个变量的值

        – 筑基_C_4 线性搜索

        – 筑基_C_5 二分搜索

        – 筑基_C_6 冒泡排序

        – 筑基_C_7 选择排序

        – 筑基_C_8 快速排序

        – 筑基_C_9 rotate()

        – 筑基_C_10 栈

        – 筑基_C_11 队列

        – 筑基_C_12 链表

Part 2 C的底层机制(性能优化)

  • 筑基_C_13 内存模型抽象

        – heap段:malloc()、realloc()与free()

        – stack段:“活动记录”

        – code段:“指令编码”
  • 筑基_C_14 微架构

        – “ALU—SFR—Memory” 结构

        – 总线

        – “流水线”
  • 筑基_C_15 汇编指令集

        – load_store类

        – ALU类

        – PC类
  • 筑基_C_16 C语言调用函数的汇编实现

        – main() 调用 foo()

        – 递归

        – C结构体和C++的类与this

        – C++函数重载的实现

        – 数据的压栈顺序
  • 筑基_C_17 预处理、编译和链接

        – 预处理:替换

        – 编译:根据.h的函数原型进行语法检查

        – 链接:去找.c→.o中的“函数实现”拼接在一起
  • 筑基_C_18 debug error

        – segment fault:使用了“段外地址”

        – bus error:地址对齐

        – debug宏函数

Part 3 程序架构模型(构建完整程序)

  • super-loop + Interrupt
  • 有限状态机
  • 多线程

        – 虚拟地址空间(MMU)

        – 时间片轮询
  • 数据在函数间的传递模式

        – 全局变量

        – 函数入参与返回值

        – 利用“内存结构”


免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

相关文章
QR Code
微信扫一扫,欢迎咨询~
customer

online

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 board-phone 155-2731-8020
close1
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

姓名不为空

姓名不为空
手机不正确

手机不正确

手机不正确
公司不为空

公司不为空

公司不为空