说起来,我大学时候C语言二级证的考试2次都不及格呢,第一次58分,第二次55分呢,所以没拿到C语言的证书。
6种位操作运算符的总结:
“&”是与字符,按位与操作,这个,就是两个2进制的进行,0跟0与以后还是0,0跟1与以后是0,1跟1与以后是1,所以两个数据的对应的2进制位,只要都是1,最后的数据就是1,只要有一个位数据是0,与以后得数据就是0了。
“|”是或字符,按位或操作,基本上跟 “&”,差不多,也是2个二进制的进行,0跟0或以后是0,0跟1或以后是1,1跟1或以后还是1,所以两个数据的对应的2进制位,只有都是0,最后的数据才是0,只要有一个位数据是1,与以后得数据就是1。
理解上, & 相当于按位做乘法, |相当于按位做加法。
“~”是取反操作,这个是对单个二进制使用的,就是0变成1,1变成0.
“<<”是左移、“>>”是右移,这个基本上是一样的,也是对单个二进制使用的,左移就是在右侧的最低位加0,去掉左侧最高位以后获得的数据,右移则是在左侧最高位加0,去掉右侧的最低位数据以后获得的数据。
“^”是异或,按位异或,也是2个2进制数的进行,0跟0和1跟1异或以后就是0,0跟1异或以后才是1。实际上是相同是0,不同才是1.
对于应用的话。
“&”跟 “|”在函数库里的算常用的, “&”是与,也就是我在if语句用的比较多一些,就是if((a==1)&(b==1)){……},表示只有两个条件都满足才能运行“{}”里面的函数,不满足的话就不运行里面函数;“|”则不同,if((a==1)|(b==1)){……},表示只要有一个条件满足了,就可以运行“{}”里面的函数,只有a跟b都不等于1的时候才不运行里面函数;
这里好像我弄错了将 “&”跟“&&”,“|”跟“||”弄混了,两个虽然都是与或,但是针对的对象不同,我一个前辈给指了出来,& 和 |是按位运算符号, && 和||是逻辑判断。“&”跟“|”是位运算, “&&”跟“||”是逻辑判断。“&”跟“&&” 相当于乘法, 任何数乘以1,都是其本身, 任何数乘以0 都是0,同理, |和|| 都是加法, 只是符号两边的数据类型不一样, &跟|两边是数据,&&跟 ||两边是逻辑式。
①“&&”与“&”的区别
“&&”和“&”都是逻辑与运算符,但同样存在一些重要的区别:
短路与(&&):在Java、C、C++等语言中,“&&”被称为短路或运算符。,短路与运算符“&&”在计算第一个操作数时,如果结果为假(false),则不会计算第二个操作数,因为整个表达式的结果已经确定为假。例如,在表达式(a > 2 && b < 1)中,如果a不大于2,则不会检查b是否小于1。所以我举的例子中是表达式,应该是用&&,而不是&。
按位与(&):与“&&”不同,“&”是按位与运算符,用于对两个整数的每一位进行逻辑与运算。只有当两个整数对应位都为1时,该位的结果才为1,否则为0。例如,对于整数3(二进制0011)和6(二进制0110),它们的按位与运算结果是2(二进制0010)。这里跟上面说的是一样的。
② “||”与“|”的区别
“||”和“|”都是逻辑或运算符,但它们有一些重要的区别:
短路或(||):在Java、C、C++等语言中,“||”被称为短路或运算符。这意味着当计算第一个操作数时,如果结果为真(true),则不会计算第二个操作数,因为整个表达式的结果已经确定为真。例如,在表达式(a == 2 || b == 1)中,如果a等于2,则不会检查b是否等于1。这种特性被称为短路计算,可以提高程序的效率。所以我举的例子中是表达式,应该是用||,而不是|。
按位或(|):与“||”不同,“|”是按位或运算符,用于对两个整数的每一位进行逻辑或运算。如果两个整数对应位中至少有一个为1,则该位的结果为1,否则为0。例如,对于整数3(二进制0011)和5(二进制0101),它们的按位或运算结果是7(二进制0111)。这里跟上面说的是一样的。
③实际应用
短路运算符:短路运算符(||和&&)通常用于条件判断,可以简化代码并提高执行效率。例如,在验证用户输入时,可以检查多个条件,并在满足第一个条件时立即停止检查。
按位运算符:按位运算符(|和&)通常用于处理二进制数据或进行位操作,如清除特定位、提取特定位、设置特定位和合并数据等。这些运算符在处理底层数据、实现特定的数据结构等方面非常有用。
所以, “||”跟“&&”运算符,用于条件判断;“&”跟“|”运算符,用于二进制数据的位操作。两种运算符运用的地方有所不同。
我当时是因为I/O口配置里面用的|,弄错了,实际运用中还是要用||。至于|等下次遇到在去分析吧。
“~”的话,我就不记得在哪里用过了。不过我觉得可以使用“~”来改变灯的亮灭,原先i不知道led灯是亮还是灭,可以加个“~=”来取反。
“<<”、“>>”,则是寄存器用到的操作,我基本上没用到寄存器编程,所以用的很少了。下面是前辈给了我一个包含位移的例子:
x|=(1<<y) 这段代码是将数据x的第y位置1, 也就是将1左移y位,再与x数据的第y位进行或,因为1跟0或者1或都是1。
x&=~(1<<y) 这段代码是将数据x的第y位清零,也就是将1左移y位,再进行取反,变成了0,然后再与x的第y位进行与,0跟0或者1与都是0.
“^”,这个我前一段时间还真用过并学习过,这个涉及到了CRC校验的研究,当时也就了解了一下CRC-CCITT的标准,并弄了一个汇总函数。我直接复制粘贴到下面,今天也就没详细看。
模式CRC16_CCITT,多项式x16+x12+x5+1(0x1021)初始值0x0000,数据位序低位在前,高位在后,结果处理:与0x0000异或
算法是数据+多项式-1位;
手工算法是发送数据+校验数据位
举例发送小写字母a的a's'cii码,二进制01100001,需要在后面添加16个0【多项式是17位】,并且除【多项式x16+x12+x5+1(0x1021)】获得的余数0111110010000111转换位16进制0x7C87即为校验码,添加到数据后面即为01100001 0111110010000111一起发送。而且因为a的十进制是97,在数组里面的第98组的位置,所以可以直接查数组获得校验码。
const uint16_t crc_table[256] ={//这个是完整的数据组,包含高低位
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};
uchar auchCRCHi[]=//这个是0x1021的高位数据组
{
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x81, 0x91, 0xA1, 0xB1, oxC1, 0xD1,0xE1,0xF1,0x12, 0x02, 0x32, 0x22, 0x52, 0x42, 0x72, 0x62, 0x93, 0x83, 0xB3, 0xA3, 0xD3, 0xC3, 0xF3, 0xE3, 0x24, 0x34, 0x04, 0x14, 0x64, 0x74, 0x44, 0x54, 0xA5, 0xB5, 0x85, 0x95, 0xE5, 0xF5, 0xC5, 0xD5, 0x36, 0x26, 0x16, 0x06, 0x76, 0x66, 0x56, 0x46, 0xB7, 0xA7, 0x97, 0x87, 0xF7, 0xE7, 0xD7, 0xC7, 0x48, 0x58, 0x68, 0x78, 0x08, 0x18, 0x28, 0x38, 0xC9, 0xD9, 0xE9, 0xF9, 0x89, 0x99, 0xA9, 0xB9, 0x5A, 0x4A, 0x7A, 0x6A, 0x1A, 0x0A, 0x3A, 0x2A, 0xDB, 0xCB, 0xFB, 0xEB, 0x9B, 0x8B, 0xBB, 0xAB, 0x6C, 0x7C, 0x4C, 0x5C, 0x2C, 0x3C, 0x0C, 0x1C, 0xED, 0xFD, 0xCD, 0xDD, 0xAD, 0xBD, 0x8D, 0x9D, 0x7E, 0x6E, 0x5E, 0x4E, 0x3E, 0x2E, 0x1E, 0x0E, 0xFF, 0xEF, 0xDF, 0xCF, 0xBF, 0xAF, 0x9F, 0x8F, 0x91, 0x81, 0xB1, 0xA1, 0xD1, 0xC1, 0xF1, 0xE1, 0x10, 0x00, 0x30, 0x20, 0x50, 0x40, 0x70, 0x60, 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0xB5, 0xA5, 0x95, 0x85, 0xF5, 0xE5, 0xD5, 0xC5, 0x34, 0x24, 0x14, 0x04, 0x74, 0x64, 0x54, 0x44, 0xA7, 0xB7, 0x87, 0x97, 0xE7, 0xF7, 0xC7, 0xD7, 0x26, 0x36, 0x06, 0x16, 0x66, 0x76, 0x46, 0x56, 0xD9, 0xC9, 0xF9, 0xE9, 0x99, 0x89, 0xB9, 0xA9, 0x58, 0x48, 0x78, 0x68, 0x18, 0x08, 0x38, 0x28, 0xCB, 0xDB, 0xEB, 0xFB, 0x8B, 0x9B, 0xAB, 0xBB, 0x4A, 0x5A, 0x6A, 0x7A, 0x0A, 0x1A, 0x2A, 0x3A, 0xFD, 0xED, 0xDD, 0xCD, 0xBD, 0xAD, 0x9D, 0x8D, 0x7C, 0x6C, 0x5C, 0x4C, 0x3C, 0x2C, 0x1C, 0x0C, 0xEF, 0xFF, 0xCF, 0xDF, 0xAF, 0xBF, 0x8F, 0x9F, 0x6E, 0x7E, 0x4E, 0x5E, 0x2E, 0x3E, 0x0E, 0x1E
};
uchar auchCRCLo[] =//这个是0x1021的低位数据组
{
0x00, 0x21, 0x42, 0x63, 0x84, 0xA5, 0xC6, 0xE7, 0x08, 0x29, 0x4A, 0x6B, 0x8C, 0xAD, 0xCE, 0xEF, 0x31, 0x10, 0x73, 0x52, 0xB5, 0x94, 0xF7, 0xD6, 0x39, 0x18, 0x7B, 0x5A, 0xBD, 0x9C, 0xFF, 0xDE, 0x62, 0x43, 0x20, 0x01, 0xE6, 0xC7, 0xA4, 0x85, 0x6A, 0x4B, 0x28, 0x09, 0xEE, 0xCF, 0xAC, 0x8D, 0x53, 0x72, 0x11, 0x30, 0xD7, 0xF6, 0x95, 0xB4, 0x5B, 0x7A, 0x19, 0x38, 0xDF, 0xFE, 0x9D, 0xBC, 0xC4, 0xE5, 0x86, 0xA7, 0x40, 0x61, 0x02, 0x23, 0xCC, 0xED, 0x8E, 0xAF, 0x48, 0x69, 0x0A, 0x2B, 0xF5, 0xD4, 0xB7, 0x96, 0x71, 0x50, 0x33, 0x12, 0xFD, 0xDC, 0xBF, 0x9E, 0x79, 0x58, 0x3B, 0x1A, 0xA6, 0x87, 0xE4, 0xC5, 0x22, 0x03, 0x60, 0x41, 0xAE, 0x8F, 0xEC, 0xCD, 0x2A, 0x0B, 0x68, 0x49, 0x97, 0xB6, 0xD5, 0xF4, 0x13, 0x32, 0x51, 0x70, 0x9F, 0xBE, 0xDD, 0xFC, 0x1B, 0x3A, 0x59, 0x78, 0x88, 0xA9, 0xCA, 0xEB, 0x0C, 0x2D, 0x4E, 0x6F, 0x80, 0xA1, 0xC2, 0xE3, 0x04, 0x25, 0x46, 0x67, 0xB9, 0x98, 0xFB, 0xDA, 0x3D, 0x1C, 0x7F, 0x5E, 0xB1, 0x90, 0xF3, 0xD2, 0x35, 0x14, 0x77, 0x56, 0xEA, 0xCB, 0xA8, 0x89, 0x6E, 0x4F, 0x2C, 0x0D, 0xE2, 0xC3, 0xA0, 0x81, 0x66, 0x47, 0x24, 0x05, 0xDB, 0xFA, 0x99, 0xB8, 0x5F, 0x7E, 0x1D, 0x3C, 0xD3, 0xF2, 0x91, 0xB0, 0x57, 0x76, 0x15, 0x34, 0x4C, 0x6D, 0x0E, 0x2F, 0xC8, 0xE9, 0x8A, 0xAB, 0x44, 0x65, 0x06, 0x27, 0xC0, 0xE1, 0x82, 0xA3, 0x7D, 0x5C, 0x3F, 0x1E, 0xF9, 0xD8, 0xBB, 0x9A, 0x75, 0x54, 0x37, 0x16, 0xF1, 0xD0, 0xB3, 0x92, 0x2E, 0x0F, 0x6C, 0x4D, 0xAA, 0x8B, 0xE8, 0xC9, 0x26, 0x07, 0x64, 0x45, 0xA2, 0x83, 0xE0, 0xC1, 0x1F, 0x3E, 0x5D, 0x7C, 0x9B, 0xBA, 0xD9, 0xF8, 0x17, 0x36, 0x55, 0x74, 0x93, 0xB2, 0xD1, 0xF0
};
uint CRC_16(uchar*data, uint len)//这个是获得的校验码
{
uchar uchCRCHi=0xFF;
uchar uchCRCLo=0xFF;
uint uindex;
While(len--)
{
uindex=uchCRCHi^data++;//这里是异或,也就是与数据进行异或来获得了CRC的高位数据
uchCRCHi=uchCRCLo^auchCRCHi[uindex];//这里是异或,也就是与高位对应的数据进行异或来获得了CRC的低位数据
uchCRCLo=auchCRCLo[uindex];
}
return(uchCRCHi<<8|uchCRCLo);//这里用到了左移8位,uchCRCHi是高八位的数据,也就是将低八位都变成0,跟uchCRCLo是低八位的数据,或一下,第八位uchCRCLo也没变化了。
}
基本上,原先给总工看了也没加注释,这会加上应该是对的吧。
“define” 这个关键词,例如#define SYSCLK_FREQ_72MHz 72000000,实际上为了更好理解,我们可以在我们程序代码里面反复使用SYSCLK_FREQ_72MHz,我们也明白什么意思,至于72000000,我们有时候不理解这个是什么意思,而且我们也可以将72000000改成8000000这种根据实际需要的变化,毕竟现在这个是系统时钟,我们可能不需要变动,但是如果是我们用的的别的函数,延时函数定义了一个数据delaynus,后来我们想增加这个数据,如果只是1个,2个数量少还能一个一个改,如果数量多的话就不好改了。
“ifdef”这个关键词,这个我还真没注意过呢,是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。
“extern”可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。 这里面要注意,对于extern申明变量可以多次,但定义只有一次。这个我之前洗板机确实用到很多呢,毕竟我将每一个项目放在一个“.C”下,数量多了,会引用到别的“.C”下的设置。特别是main主函数肯定用到分函数的数据的。
“typedef”,定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。这个实际上也可以不用,毕竟也就是划分规整就是了。
结构体:构造类型:以前绝对不会用的,这里先整理一下吧,慢慢再深入了解。
同一个类型可以用数组,不同类型可以用结构体组织。结构体可扩展性强。好像是加变量,不需要再对现有函数进行改变。在以后的开发过程中,如果你的变量定义过多, 如果某几个变量是用来描述某一个对象,可以考虑将这些变量定义在结构体中,这样也许可以提高代码的可读性。
这个先复制到这些,好像正点原子以后还有详细讲解,到时再详细描叙。
“static”,申明的局部变量,存储在静态存储区。 它在函数调用结束之后,不会被释放。它的值会一直保留下来。 所以可以说static申明的局部变量,具有记忆功能。之前按键那里学习到这个的应用,没有加“static”变量以后每次都有一个复位,恢复我们函数里面设置的数据,如果加“static”以后,就只会开始时候运行一次我们设置的数据,之后就变成了累计功能,每次运行的时候会加载上一次运行以后得数据。
int getValue(void) { int flag=0; flag++; return flag; }//flag每次进入这个都会是0,所以flag只有0跟1两个数据
int getValue(void) { static int flag=0; flag++; return flag; }//flag只有第一次进入这个函数才会是0,之后每次进入函数会累计加1,所以flag如果可以的话可以变成无穷大。
补:就先到这里吧,希望对看到的大家有帮助。