- 打卡等级:以坛为家II
- 打卡总天数:510
- 最近打卡:2025-05-06 08:17:28
中级会员
- 积分
- 424
|
发表于 2023-9-5 17:12:11
|
显示全部楼层
2023/09/05 何老师 C语言课程打卡记录
当使用指向const对象的指针时,可以在指针定义中排除 const类型限定符,例如:
const unsigned char mask[]={0x01, 0x02, 0x04, 0x08);
const unsigned char *cp=mask;
unsigned char *p=mask; // 与cp效果相同
*p=' a,; 〃这里没效果,不会导致警告或错误
*cp=,a'》; 〃这会导致错误
从上面可知,可以将常数对象mask的地址分配给非常数的指针p,然后使用该 指针更改常数对象。在这种情况下,编译器会生成代码写入常数对象。该代码的 效果未定义,可能或无法按预期工作
不能使用const指号供更改它指向的常数对象。如果这样做,将导致编译器错误
■该程序使用两个变量(reg1和reg2)访问硬件寄存器
■在大多数情况下,编译器将reg1加载到寄存器中,并且不会在循环迭代之 间重新读取它(即使硬件寄存器可能正在更改)
■此外,对reg2的三个赋值可以简单的优化为最终的赋值(前两个赋值不生 成代码)。这些影响是由优化器造成的,而不是编译器生成的错误
■事实上,这些是编译器应该进行的优化类型。然而,在这种情况下,它们 肯定是不可取的
【例8-6】数组元素存储和运算的C语言代码
void main()
{
const char code table[]={1,2,4,8};
volatile char i=0,sum=0;
for(i=0;i<4;i++)
sum+=table;
}
■该C语言代码对应的反汇编代码
1: void main()
2:{
3: const char code table[]={1,2,4,8};
4: volatile char i=0,sum=0;
0XFF0003 E4 CLR A
0XFF0004 7AB30008 MOV j(0x0008),R11
0XFF0008 7AB30009 MOV sum(0x0009),R11
5: for(i=0;i<4;i++) }
0xFF000C 8021
SJMP C:0x002F
第二部分
C语言支持许多可以应用于程序变量的存储类
■存储类用于定义变量和函数的范围和生存周期,这些存储类关键字包括:
■ auto
■ register
■ static
■ extern
auto存储类是本地变量默认的存储类
■其格式如下:
auto data-type name <[>=value<]>
其中
■ data-type为变量的数据类型
■ name是变量的名字
■ value是分配给变量的值
需要注意,存储类auto只能在函数定义内使用
register存储类定义了应该保存在一个或多个寄存器中而 不是RAM中的局部变量
■其格式如下:
register data-type name <[>=value<]>;
其中
■ data-type为变量的数据类型
■ name为变量的名字
■ value为分配给变量的值
■通常,C251编译器忽略register存储类。如果有可能,所有变 量都保存在寄存器中
注:存储类register只能在函数定义内使用
static 存储类限制变量的范围并修改局部变量的生存期
■其格式如下:
static data-type name <[>=value<]>;
其中
■ data-type为变量的数据类型
■ name务变量的名字
■ value是分配给变量的值
■使用static在函数外部声明变量时,无法在声明变量的源文件外部访问该变量
■当使用static在函数内部声明变量时,该变量在启动时就被初始化(与其他全局变量一样),并且在调用该函数时保留其值
■在进入函数时它不会被重新初始化
extern存储类声明在另一个源模块中定义的全局变量
■其格式如下:
extern data-name name;
其中
■ data-type为变量的数据类型
■ name为变量的名字
■当使用extern声明变量时,无法初始化该变量,这是因为它已经在定义的位置初始化了
【例8-7】存储类用法的C语言描述
在extern.c文件中定义变量
short int a=3000,b=-2000;
在main.c文件中调用外部变量
#include "math.h"
extern short int a,b;
void main()
{
volatile long int c;
c=a*b;
}
下一节,静态变量 在整个程序运行中状态和含义。
static:
int i=0;
int cal(int x)
{
static int y=0;
y=x-y-i;
return y;
}
void main()
{
int j=1000;
i=cal(j);
i=cal(j);
i=cal(j);
}
变量可以使用_at关键字定位在绝对存储器的位置
■其格式为:
type[memory_type] variable_name _at_ const_expr;
其中
■ type为变量的类型
■ memory_type为变量的存储器类型。如果在声明中排除该项,则使用默 认存储器通
■ variable_name为变量的名字
■ const_expr为必须计算为绝时常数值的表达式。表达式的结果是定位变 量的地址
随在_at_关键字后面的绝对地址必须符合变量存储空间的 物理边界,
■对于xdata和code存储器类型,该表达式解释为相对于存储器类 型的基地址的偏移量
■ C251编译器为xdata和code变量生成OFFS重定位类型
■对于其他存储器类型,_at_表达式表示STC32G系列单片机中的 绝对存储器位置
■ C251编译器检查地址范围是否有效
第三个内容 :指针 ******p
C251编译器支持使用*字符声明变量指针
■ C251编译器可用于执行标准C中可用的所有操作
可以在指针声明中使用存储器类型来定义指针的大小
■没有显式存储器类型的指针称为通用指针
■具有显式存储器类型的指针称为存储器特定指针
■特定于存储器的指针为每个变量访问生成更高效的代码
■指向data或idata对象的指针可以使用near存储器类型声明
■因为near指针也可以访问data或idata存储器
■在TINY和XTINY存储器模型中,默认指针大小为16位,指针的 默认存储器类型为near*
■要访问0x010000以上的存储器区域,必须在指针声明中指定存储器类型 为far *或huge *
■使用far或者huge指针,可以寻址near、data或idata对象。
不同之处在于
■ far或huge指针访问使用@DPk指令,然而near指针使用更高效的 @WRj指令
■ far或huge对象不能用near指针寻址
下面给出一些使用例子:
■ char near *px;
■声明一个指针,该指针引用near存储器类型中char类型的对象。指针本 身保存在默认存储器类型中(取决于使用的存储器模型).大小为两个字
■ char near *data pdx;
■该声明与先前的声明相对应,只是指针本身被明确地放置到数据存储器 (data)中,而与使用中地存储器模型无关
■ int (* xdata fp) (void);
■该声明定义了函数指针,该函数指针被显式放置到xdata存储器类型中, 而与使用地存储器模型无关。所寻址的函数的类型为void func (void)
struct ptime{
char hour;
char min;
char sec;
struct time near *pxtime;
};
■除了其他元素之外,该结构还包含指向另一个结构的指针pxtime,该结 构必须位于near存储器类型中。指针pxtime的大小为两个字节
■ struct time far *ptime;
■该声明定义了一个指针,该指针保存在默认的存储器类型中,并引用位于 far存储器类型中的struct time。指针ptime需要四个字节
■ ptime- > pxtime- > hour = 12;
■使用前面的两个声明。指针pxtime是从结构间接加载的。它指向struct time,位于near存储器类型。将值12分配给该结构的成员hour
C251编译器可以转换指针的存储器类型
■指针转换可以由使用建型强制转换的显式程序代码强制执行,也可以由编译器强制执行
■通用指针与TINY或XTINY存储器模型的near *指针定义相同。对于所有 其他存储器模型,通用指针与far *指针定义相同
当存储器特定指针作为参数传递给需要通用指针的函数时,
C251编译器将存储器特定指针转换为通用指针
■ C251运行时库函数(如printf、sprintf和gets)的情况就是如 此,这些函数使用通用指针作为参数
■例如:
extern int printf (void *format,...);
extern int myfunc (void near *p, int data *dq);
int data *dp;
const char near *fmt = "value = %d | %04XH\nM;
void debug print (void) (
printf (fmt, *dp); // 转换fmt
myfunc (fmt, nx); // 没有转换
}
■在对printf的调用中,表示2字节near指针的参数fmt被自动转 换成强对为通用指针
■这样做是因为printf的原型需要一个通用指针作为第一个参数。根据存储 器模型,通用指针的大小为2个字节或4个字节
注:在TINY或XTINY存储器模型中,无法使用标准C251运行时库函数访问 0x010000以上的存储器位置。因此,printf的格式字符串必须声明为const char near.如果将格式字符串声明为char code (如C51程序中所做的那样), 则printf仅适用于SMALL. XSMALL或LARGE存储器模型
■由于将地址空间看作是线性实体,因此指针转换主要通过扩展或截断指针的高位部分完成
|
-
|