关于C语言的相关问题说而明:本内容涉及到单片机的内容都是关于8051和keilC51编译器。C 程序开发步骤:编辑一一编译一一连接一一运行。编辑就是程序代码的录入,生成源程序*.c 一编译就是语法分析查错,翻译生成目标程序.obj,由编译器完成一连接就是与其它目标程序或库链接装配,生成可执行程序*.exe源程序目标程序可执行程序内容程序设计语言机器语言机器语言格式ASCII二进制二进制可执行不可以不可以(因不含库文件和其它目标文件)可以文件名后缀.c 或.cpp.obj.exe说明:C 语言编制的单片机程序在编译时,C51要求先产生一个汇编语言源文件,再编译此汇编文件。用 C 语言和汇编混合编制的程序,位于#pragma a sm 和#pragma endasm 之间的汇编段或汇编语言编写的函数是用A 51编译,C 程序是用C51编译,然后用L51连接成.obj。*.asm是汇编语言程序若在window中使用写字板编写程序,也是ASCH格式,但要存为*.c文件,不能存为*.txt格式。一、运算优先级:1、运算符的优先级:C语言中,运算符的运算优先级共分为15级。1级最高,1 5 级最低。在表达式中,优先级较高的先于优先级较低的进行运算。而在一个运算量两侧的运算符优先级相同时一,则按运算符的结合性所规定的结合方向处理。2、运算符的结合性:C语言中各运算符的结合性分为两种,即左结合性(自左至右)和右结合性(自右至左)。例如算术运算符的结合性是自左至右,即先左后右。如有表达式x-y+z则y应 先 与 号 结 合,执 行x-y运算,然后再执行+z的运算。这种自左至右的结合方向就称为“左结合性”。而自右至左的结合方向称 为“右结合性”。最典型的右结合性运算符是赋值运算符。如x=y=z,由于“=”的右结合性,应先执行y=z再执行x=(y=z)运算。C语言运算符中有不少为右结合性,应注意区别,以避免理解错误。C语言中的算术表达式只能由运算符、圆括号、系统函数和运算对象构成,运算的顺序不但受优先级控制,还受结合性的影响,如上例中的:x-y+z;C语言中有15个优先级,在表达式中,优先级高的先于优先级低的运算,在一个运算量两侧的运算符优先级相同,则按运算符的结合性规定的结合方向处理。如:a+b*(a+2)/c*(b+3).运算符:单目,双目、三目关系运算符都是双目运算符,其结合性均为左结合。关系运算符的优先级低于算术运算符,高于赋值运算符。在六个关系运算符中,,=的优先级相同,高于=和!=,=和!=的优先级相同。!(非)-算术运算符一关系运算符一&和II-*赋值运算符“&”和 低 于 关 系 运 算 符,“!”高于算术运算符。逻辑运算符也有优先级别,!(逻辑非)f&(逻辑与)一|(逻辑或),逻辑非的优先值最高。C语言中的以上三个逻辑运算的结果是波尔值“真”或“假二位运算符也有优先级,从高到低依次是:“”(按位取反)一“(右移)一(按位与)一“人”(按位异或)一 T (按位或)以上的位运算符运算按位运算后的结果是具体的数,8051汇编语言中的ANL、ORL、XRL等按位运算后运算的结果也是具体的数值。优先级 运算符 结合性(最高)().自左向右 1级!+-*(取 值)、&(取地址)s i z e of自右向左 2级*/%自左向右 3级+-自左向右 4级 自左向右 5级=自左向右 6级=!=自左向右 7级&自左向右 自左向右I自左向右&自左向右 11级I I自左向右 12级?:自右向左 13级 唯一的三目运算符,格 式:逻辑表达式?表 达 式1:表达式 2 如:m a x=(a b)?a:b;将条件运算符的结果赋给 m a x.条件运算符可嵌套,如:嵌套:x 0?l:(x0?T:0)赋值和复合赋值运算符:=,+=,-=,*二,/=,二,&=二,仁,=,=自右向左赋值运算符左边必须是变量。连 续 赋 值 如:a=b=c=l不能在定义时使用。格 式:变 量 名 复 合 赋 值 运 算 符 表 达 式,其含义就是变量与表达式先进行运算符所要求的运算,再把运算结果赋值给参与运算的变 量。其 实 这 是C语言中一种简化程序的一种方法,凡是二目运算都能用复 合 赋 值 运 算 符 去 简 化 表 达。例 如:a+=5 6 等价于 a=a+5 6派y/=x+9等 价 于y=y/(x+9)把赋值运算符右边看为一个整体。,运算符:自左向右(1 5级最低)逗号在C语言中的作用作两种:1、一种就是起隔离作用;2、在C语言中逗号还是一种特殊的运算符,也就是逗号运算符,能用它将两个或多个表达式连接起来,形成逗号表达式。逗号表达式的一般形式为:表 达 式,表达式 2,表达式 3.表达式 n这样用逗号运算符组成的表达式在程序运行时,是从左到右计算出各个表达式的值,而整个用逗号运算符组成的表达式的值等于最右边表达式的值,就是“表 达 式n”的值。si z e o f 运算符:奇怪的运算符,有点像函数,却又不是。si z e o f 是用来求数据类型、变量或是表达式的字节数的一个运算符,但它并不像“=”之类运算符那样在程序执行后才能计算出结果,它是直接在编译时产生结果的。它的语法如卜:si z e o f (数据类型或变量或是表达式).二、数据类型及其转换:C语言的数据分为常量和变量。标识符定义和命名规则定义:标识变量名、符号常量名、函数名、数组名、文件名的字符串序列名字。命名规则:只能由字母、数字、下划线组成,且第一个字符必须是字母或下划线大小写字母含义不同,一般用小写,不能使用关键字。C语言大小是敏感的,同一个字母大和小写被认为是两个不同的数据。关键字一般都是小写。TC允许最长3 2个字符,建议长度不超过8个字符使用:先定义、后使用。1、数值数据有两种:整数和浮点小数整 数(包含整型常数)的三种表示方法:十进制整数:由数字09 和 正 负 号 表 示.如 123,-456,0八进制整数:由数字0 开头,后跟数字07 表 示.如 0123,011 十六进制整数:由 Ox开头,后跟。9,af,AF 表示.如 0 xl23,0 xff在C 语言中计算超出数据类型的范围就溢出,但是系统不报错,编译时要注意。如:整型变量最大值32767,加 1 后 是-32768的补码形式。浮 点 数(flo a t、double)不 能 用“=0”进行关系判断,用=10-6;单精度float有效数字67位,双精度double型有效数字1516位.浮点型常量一般按双精度64位处理,数后加F 或 f 按单精度;浮点型常量不分float和double ddd:3 位 8 进制数代表的字是ASCII表中该数值所对应的字符。xhh:2位16进制数代表的字是ASCII表中该数值所对应的字符。字符数据在内存中的存储形式及其使用方法 单个字符常量是用单引号括起来的,以二进制存放字符的ASCII码值(0255整数)如:a 存的就是65,反斜杠加字符是转义字符,单个转义常量也是用单引号括起来,如:n,表示换行,表示单斜杠,表示单引号,表示双引号。字符串是用双引号括起来的单个或多个字符,从左到右以二进制存放字符的 ASCII码值,字符串常量或自后边自动加一个空字符“0”,实际占有空间是实际字符数(空格也算)+lo与 整数的存储形式类似字符数据可以字符或整数形式输出;字符型与整型间互相赋值。如:int i;char a;i=A;i 的值是A在 ASCH表中对应的65;a=65,a 的值是65在 ASCH表中对应的A;a=,9;把 9 当作字符赋给了a ,a在存储器中存的是字母9就对应的5 7的值。表达式返回的结果值是有类型的。表达式隐含的数据类型取决于组成表达式的变量和常量的类型。类型转化的原则是从低级向高级自动转化(除非人为的加以控制)。计算的转换顺序基本是这样的:字符型一 整型一 长整型一 浮点型一 单精度型一 双精度型就是当字符型和整型在一起运算时,结果为整型,如果整型和浮点型在一起运算,所得的结果就是浮点型,如果有双精度型参与运算,那么答案就是双精度型了。将一个浮点小数赋给一个整型变量,则小数部分被舍去,如:i n t a=6.5;实际存的a的值是6。将一个整数数据赋给一个fl o a t型,整数部分不变,后边加小数点和0,如:fl o a t a=1 2;a=1 2.0 0 0 0 0 0 字符变量可以给它赋字符常量、-1 28 1 27之间的整数或转义字符。强制转换是这样的,在类型说明符的两边加上括号,就把后面的变量转换成所要的类型了。如:(i n t)a;(fl o a t)b;第一个式子是把a转换成整型,如果原先原小数部分,则舍去。第二个式子是把b转换成浮点型,如果原先是整数,则在后面补0。每一个表达式的返回值都具有逻辑特性。如果返回值为非0,则该表达式返回值为真,否则为假。2、C语言有四种对数据类型进行修饰的符号l o n g 长型、s h o r t 短型、s i g n ed 有符号型、u n s i g n ed 无负号型。L o n g 般修饰 i n t、d o u b l e:i n t 2 个字节,1 6 位;L o n g i n t 4 个字节,32 位;d o u b l e 8 个字节,6 4 位,L o n g d o u b l e 1 6 个字节,1 28 位。s h o r t 一般修饰 i n t,s h o r i n t 2 个字节,1 6 位。s i g n ed 和 u n s i g n ed 一般 修 饰(l o n g、s h o r t)i n t、c h a r,表示是否是带符号数,最高位是否负号位。3、关于补码存储问题计算机中数据是以补码形式存储的,正数的补码是本身,负数的补码要转换,但是机器不能区分正负,C P U它 只 识 别 0、T,由于计算机是用高级语言编写程序,所以把负数转换为补码存储是编译系统完成的,但汇编语言是直接面对机器编成,使 用 的 是 助 记 符 和1 6进制操作数,没有数据类型,没有明确的正负数标记,机器本身不能区分正数和负数,数据的正负都在程序员的心里,程序员认为是正数就按正数规则处理,认为是负数就按负数规则处理,单片机的加减程序运算各位都参与计算,机器是按无符号数处理,加 减 判 断 溢 出 是 看0 V,0 V溢出是按负数以补码参与运算的情况下进行判断的,要进行有符号数运算,必须把负数转换为补码进行,所以用户先要将负数变成补码存入,再进行加减,然后根据0 V的 情 况 进 行 修 正(用户软件)。0 V溢出是建立在补码基础上判断的,所以一 旦0 V溢 出 后,说明有效位不够,要 增 加1位有效位,然 后 根 据C y判断数的正负,最 后 再 求 该 数 的 补 码(C P L+1),才能得到实际的数。有效位的多少决定求补的数值,如:1 0 1补码是:1 1 1 (-3),1 0 0 1补码是:1 1 1 1 (-7)高级语言不用用户干涉,转换和修正是编译系统进行,因此在高级语言中要输 入 负 数 就 要 在1 0进 制 数 前 加 上 负 号“-明 确 标 记,若标记为负数则编译系统将 其 变 成2进制补码存入,如:c ha r a=-1,存入的就是口1 1 1 1 1 1 1 (c ha r类型一个字节),如:i n t a=-l,存入的就是类型两个字节),若 无 负 号(正数不加+)编译系统是按正数处理,直 接 转 换 为2进制存入,如:i n t a=1 2 7,存入的就是 冰)0 0 0 0 0 0 0 1 1 1 1 1 1 1;在C语言中超出数据类型的范围就 溢 出,但是系统不报错,超出该类型总长的部分丢失。如:c ha r a=1 2 9,超出-1 2 8 1 2 7范围,但 编 译 系 统 转 换 为2进制为0 1 0 0 0 0 0 0 1,符号位“0”丢失,存 入1 0 0 0 0 0 0 1,最高位是1,因a是c ha r类型,是有符号数据,若用%C 格式输出,编译系统把最高位1看为负号