标签:style blog http io os ar 使用 for strong
#ifdef RTMP_MAC_PCI
2.使用嵌套宏定义的时候,自己的习惯,只使用这一种嵌套定义的方式。pDrvOps->RTMPHandleInterrupt = RTMPHandleInterrupt;
#endif // RTMP_MAC_PCI //
当编译器遇到#warning和#error这两个时,会分别产生一个警告和错误
遇到warning的指令时,会给用户显示#warning指令后面的文本,之后编译继续。
遇到error的质量时,会给用户显示#error指令后面的文本,之后退出编译
#warning
#if defined(A)
#elif defined(B) || defined(C)
#else
#error "You must specify the Board Version!!\n"
#endif
#if DEBUG && RELEASE #error "You‘ve defined DEBUG and RELEASE simultaneously! " #endif
以上的宏定义,如果同时定义的DEBUG和RELEASE的话,那就在编译过程中就报错。
利用编译器的预编译检查作用来控制多版本的编译使用说明。
3.在原有代码的基础上,进行自己的修改,需要加上自己的修改时间以及其他必要的信息。如果与其他内容相重叠,则用#if 0注释掉原有的代码,千万不能删除掉原有的代码
/*start modified by hu hao at 2013-10-28*/
//简要的修改说明
自己修改的内容
/*end modified by hu hao at 2013-10-28*/
4.用git或者svn管理自己的代码。
用git来建立本地仓库和远程git的repos中心仓库,操作方法如下:
在本地新建一个目录,git_test,然后执行 git init。
在其他地方新建一个git的repos中心仓库目录,然后执行 git clone --bare git_test目录所在的位置,就建立好的自己的一个git的repos中心目录。
后面,可以在git_test里面做相应的修改,然后git push就可以了。
git clone 指定自定义远程库的路径就可以下载保存在库中的资料的。
5.多个文件的调试信息,用一个统一的控制宏来控制
6. 类似与这样的宏定义,如果不用其中一条,则必须要完成去掉,不能只是注释掉,要全部去掉。
#define INIT_DISK_SPINDOWN(arg)
do{
arg.vs_disk_spin_lock = SPIN_LOCK_UNLOCKED;\
arg.vs_timer_cnt = 0;\
arg.vs_disk_spindown_flag = 0;\
arg.vs_usb_suspend_flag = VS_USB_SUSPEDN_DISABLE; \arg.vs_disk_spindown_flag_last_timer = 0; \
arg.vs_sd_spindown_flag = 0;\
arg.vs_sd_rw_cnt = 0;\
}while(0)
7.内核打印提示采用如下方式,更加清晰,便于找错。
printk(KERN_INFO "[%s,%d] prepars ssd, 0x%x\n", __FUNCTION__, __LINE__, vs_get_usb_suspend_state());
printk(KERN_INFO "[file:%s func:%s line:%d] e = 0x%x.\n", __FILE__, __FUNCTION__, __LINE__, status);
8.以后,在自己开发的模块中,一定要有可以动态打开调试信息,动态使能模块和动态禁止模块的三项功能。对于每一个自己实现的内核模块来说,要有一个proc文件,读取它时,可以显示自己模块里面的相应的必要信息。往里面写入时,就是动态的执行模块的控制命令的过程。这样,便于测试部门的使用和自己的开发。正式发版时,是关闭debug和开启模块功能的。
9.使用vi+ctag来快速浏览源码
ctags -R // 递归创建
l 用#define定义的宏
l 枚举型变量的值
l 函数的定义、原型和声明
l 名字空间(namespace)
l 类型定义(typedefs)
l 变量(包括定义和声明)
l 类(class)、结构(struct)、枚举类型(enum)和联合(union)
l 类、结构和联合中成员变量或函数
1.使用 vi -t foo_bar //将打开foo_bar(变量或者函数或者其他)
2.在vi的命令行中:ta foo_bar
3.光标移到需要定位的变量名上,Ctrl+](右括号)查找,Ctrl+o退回到原来的地方 原来这个功能好强啊
当前在第11个标签处。
Ctrl+T回到上一个标签处,
:tfirst 到第一个匹配
:[count]tprevious 向前 [count] 个匹配
:[count]tnext 向后 [count] 个匹配
:tlast 到最后一个匹配
10.驱动开发头文件中,要有自己定义的调试信息输出,借鉴MTK源码驱动里面的实现,如下:
//#define DEBUG_INIT_MODE //开启驱动中,输出模块功能的默认输出内容
//#define SPDIF_DEBUG_PRN //开启MSG调试信息输出
#ifdef SPDIF_DEBUG_PRN
#define MSG(fmt, args...) printk("SPDIF: " fmt, ## args) //指定调试信息输出模块名
#else
#define MSG(fmt, args...) { }
#endif
在调试写入写出寄存器时,可以如下:
#ifdef SPDIF_DEBUG_PRN
#define spdif_outw(address, value)
do{printk("0x%08X = 0x%08X\n",(u32)address,(u32)value);*((volatile uint32_t *)(address)) = cpu_to_le32(value);}while(0) //写入寄存器的值
#else
#define spdif_outw(address, value) *((volatile uint32_t *)(address)) = cpu_to_le32(value)
#endif
#define spdif_inw(address) le32_to_cpu(*(volatile u32 *)(address)) //读出寄存器的值
对于一个功能模块,要定义全部的控制寄存器以及每一个在datasheet中起作用的控制位的名称
例如:
/* Register Map Detail - SPDIF*/
#define IEC_CTRL (RALINK_SPDIF_BASE+0x0000)
#define IEC_BUF0_BS_SBLK (RALINK_SPDIF_BASE+0x0004)
/* IEC_CTRL bit field */
#define RAW_EN 31
#define RAW_EN_OPT 30
提供给上层的ioctl的命令定义以及使用说明,以及在驱动文件中使用到的函数的声明。
11.在编译Uboot和kernel时,当采用了新的.config配置文件时,一定要执行make menucofnig,重新读取.congfig配置文件,用来生成新的autoconf.h的文件,如果更改了其他配置,在生成镜像后,需要拷贝其他的config配置文件成为.config的话,一定要执行make menuconfig来重新生成autoconf.h配置文件
12.如果在编译连接时出现错误,不要心慌,不要心急,从最简单的入手,一个一个的添加编译,人工手动的加入一些编译错误,查看该文件是否被编译进去了,是否调用了正确的值。
13.
#pragma message 。 它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:
#pragma message(“消息文本”)
#ifdef CONFIG_TEXT
#error "this error will block the compilering process.."
#endif
当遇到一些连接的问题时,本来自己添加的头文件,想引用结果还是没有找到,可以在
解决问题的思路:common/vs_cfg.c里面调用drivers/i2c_drv.c里面的函数,出现错误。
1.在common目录下新建一个测试文件,hello.c hello.h,然后再vs_cfg.c里面调用hello.c里面的函数,编译通过。
2. 将i2c_drv.c里面的函数一个一个拷贝到hello.c里面去,在vs_cfg.c里面调用这里的函数,看有没有问题,如果没问题,继续下面的。
3. 在对于的Makefile里面,查看这两者的编译顺序
小技巧:主动写一些错误的代码,利用编译器的查错功能来检测,这部分代码是否被编译进去了。
14:
15、
16. 内核出错提示信息相关函数.
rtc_class = class_create(THIS_MODULE, "rtc");
if (IS_ERR(rtc_class)) {
printk(KERN_ERR "%s: couldn‘t create class\n", __FILE__);
return PTR_ERR(rtc_class);
}
对于内核中,返回值为指针数值的情况,有三种情况,有效指针,无效指针(非空),NULL指针。
内核函数返回的正确指针一般是指向页面边界的4K对齐的,也就是ptr&0xfff == 0,这样ptr的值,不可能落在0xffff_f000(-1000的补码)~0xffff_ffff之间了。用(unsigned long )ptr > (unsigned long)-1000L就可以来判断了。
内核在include/linux/errno.h中定义了一些错误返回码的值,实际程序出错时,返回加上一个负号。
#define ENOLCK 77
#define ENOSYS 78
#define ENOMSG 80 ...void perror(const char *s)会先打印出s所指示的字符串,然后将上一个函数的错误信息输出到标准错误输出(stderr),
在库函数中有个error变量,每个error值对应着以字符串表示的错误类型,
当你调用"某些"函数出错时,该函数已经重新设置了error的值。perror函数只是将你输入的一些信息和现在的error所对应的错误一起输出
例子:#include <stdio.h>
int main(void)
{ FILE *fp ;
fp = fopen( "/root/noexitfile", "r+" );
if ( NULL == fp )
{
perror("/root/noexitfile");
}
return 0;
}
输出结果:/root/noexitfile: No such file or directory
使用fprintf
int fprintf(FILE *restrict fp, const char *restrict format, ...);
所谓流,通常是指程序输入或输出的一个连续的字节序列,设备(例如鼠标、键 盘、磁盘、屏幕、调制解调器和打印机)的输入和输出都是用流来处理的,在C语言中,所有的流均以文件的形式出现——不一定是物理磁盘文件,还可以是对应于某个输入/输出源的逻辑文件
17.drivers/char/vs_pio.c:725: error: dereferencing pointer to incomplete type
试图访问该pointer指向的变量,却发现该变量是一个不完整的类型,多出错于访问结构体联合体的成员
#include <linux/mmc/host.h>
...
extern struct mmc_host *g_mmc_host_p; //这个指针的结构体定义在 mmc/host.h里面,在vs_pio.c里面引用。
if( (g_mmc_host_p != NULL) && (g_mmc_host_p->card != NULL)){ //在访问这个指针对指向的结构体的成员时,报错。
extern void mmc_sd_unmount(void);
mmc_sd_unmount();
sd_printk("SD card success unmount!\n");
}else{
//sd_printk("SD card success mount!\n");
}
解决方法:
1. 先试图找一个那个结构体的定义文件是否能找到,用grep "struct xxx" /usr/include -R来递归寻找或者使用vi -t mmc_host来寻找,找到后再include这个头文件就可以。标准头文件用include 来包含就可以,非标准头文件用相对路径来包含或者用绝对路径,编译时-I/usr/local/xxx/include来包含
2.如果include后仍然出错,仔细查看该头文件,看是否被编译宏给包含了。如果确实包含了,在编译时,加上-D_USE_BSD来包含。
18.出现问题时,先要准确描述问题,就这几天遇到的问题做一个总结。
问题描述:
SD卡读写数据时,插拔SD卡,不能卸载完全,proc/partitions下面还有残留的信息。
在代码里面寻找SD卡拔出时的处理流程...在每一个关键的路径下面加上打印调试信息,确定问题发生链,打开所有的log信息,复现出bug。
bug发生时:在本该进入的路径,确没有进入的情况,即可定位为出现问题的原因。
解决方法:在执行拔出动作时,缩短执行函数的时间,
从黄工给出的解决思路来看,1.尝试着插拔时,禁止中断。--->尝试失败
2. 注释掉自己增加的一些功能--->没有效果
3.进入中断拔出时,上次有卡,这次没卡,那就重新执行一次唤醒一次拔出的流程。上一次有卡,这一次没有卡,则执行如下操作。
19.C++中调用C函数代码
统一的解决方法:
__cplusplus是c++编译器内置的标准宏定义,让c代码既可以通过c编译器的编译,又可以在c++编译器中以c的方式进行编译(使用条件编译),代码如下:
20. 当测试与底层硬件有交互的程序时,尽量先手动设置硬件那边的返回值,前期在软件上面测试,等待可以通过任何硬件的返回值(有效值和无效值)后,再和硬件联合调试。
21:C++的命名空间
C++的命名空间用于控制全局变量的作用域,并且可以指定引用的命名空间。
1.
定义一个名称为hao的命名空间
namespace hao{
int a = 9;
}
2. 使用这个命名空间
只使用这个变量 hao::a
全部使用 using namespace hao;
运算符的优先级问题、多线程编程中各个线程的交互、强制类型转换
22.构造函数和析构函数
C++编译器会为每个类默认生成四个辅助函数,构造函数,拷贝构造函数,析构函数和赋值操作符,并且,编译器只在需要的时候生成默认构造函数。
1.默认的构造函数为无参数,无返回值,函数体为空。定义类的方法为:list a 或者 list a = list()
兼容那些没有定义构造函数的类的定义。
2.默认的拷贝构造函数,参数为自己类的引用的构造函数。如list (const list& l).功能为进行简单的成员变量的值的复制,只在list b = p。p为已经定义的对象(已经初始化),b为新定义的对象,要求b拥有和p相同的成员变量时才会被调用。可以自己定义拷贝构造函数来实现自己要想的功能。
无参数的构造函数,有参数的构造函数,拷贝构造函数之间的关系是重载的关系,使用方式如下:
list a list a(5) list b = a或者 list b(a)
自定义的拷贝构造函数不仅会覆盖默认的拷贝构造函数,也会覆盖默认的构造函数
3.默认的析构函数,在对象撤销的时候,对象对自动调用一个析构函数,无参数也无返回值。
~list()
析构函数的调用顺序是与构造函数的调用顺序完全相反的。每一个对象都有构造函数和析构函数。析构函数则需要程序员自己手写
4.静态成员变量和静态成员函数
为了在类的多个对象之间共享变量以及简单的通知,提出了静态成员变量和静态成员函数的概念。
静态成员属于整个类所有,不需要依赖任何对象。可以通过类名直接访问public的静态成员,也可以通过对象名访问public的静态成员
静态成员函数可以直接访问静态成员变量或者全局变量。
参考网址:http://blog.csdn.net/mbh_1991/article/details/17377361
第一:在函数参数与类中成员变量重名的时候,使用this指针来访问成员变量。
第二:当你想通过函数返回本对象或者保存本对象的时候,就要使用*this来访问本对象。
实现代码抽象和重用,分析执行一项操作的步骤,提取通用的部分,然后合理利用
GPS学习网址:http://blog.csdn.net/eastmoon502136/article/details/8562934
把自己看过的知识总结成图表来帮助记忆以及加深理解。
千言万语抵不过一张精美绝伦的图,不对自己狠一点,就不知道自己有多优秀。
23.mount --bind
为了测试某个新功能,必须修改某个系统文件,而这个系统文件又是在只读文件系统中,或者是虽然是这个文件是可写的,但是对这个修改没有把握,只想暂时的修改,作为测试,此时 mount --bind指令就非常的有用了。
23.1 替换已经存在的文件内容。
比如要修改只读文件系统中的 /etc/hosts文件,将修改后的文件放到/tmp下,也可以放在硬盘或者U盘中。
mount --bind /tmp/hosts /etc/hosts ;意思是暂时用 /tmp/hosts内的内容代替/etc/hosts里面的内容
此时,/tmp/hosts就和/etc/hosts两个文件的内容是一致的了,两者的修改会自动同步。修改完成后,
使用 umount /etc/hosts 就可以解开绑定了。/etc/hosts内的内容和原先一样。
23.2增加一个不存在的文件内容,比如在/etc目录下 新增一个export文件。
1.先绑定整个/etc/目录,绑定前先复制另一个目录。然后用mount --bind重定向来访问
cp -a /etc/ /tmp/
mount --bind /tmp/etc/ /etc/
对后者的访问重定向到前者来。
操作完成后,要 umount /etc/
2.挂载ramfs到/etc/
mkdir /tmp/etc/
mount -t ramfs none /tmp/etc
将只读模式重新挂载为读写模式。
mount -o remoun,rw /tmp/usbmounts/sda1
变量的类型决定变量的行为(在没有虚函数的前提下),
泛型编程:
不考虑具体数据类型的编程模式,和普通编程的主要区别是类型可以被参数化。
函数模板:template,关键字,用于开始进行泛型编程
typename 用于声明泛型类型
例子:
template <typename T>
void Swap(T&a , T&b){
T t =a;
a = b;
b = t;
}
两种调用方式:
int a=1,int b=4; Swap(a,b) //自动类型推导
float b=3.4,c=9.3 Swap<float>(b,c) //显示类型调用
1.利用addr2line加debug版的内核来准确定位同名函数
编译一个带有调试信息(选中 CONFIG_DEBUG_INFO)的内核镜像vmlinux,执行下述命令:
比如要找 init_IRQ这个同名函数
查找通过函数指针调用的函数调用链条。
标签:style blog http io os ar 使用 for strong
原文地址:http://www.cnblogs.com/cherishui/p/4032460.html