码迷,mamicode.com
首页 > 其他好文 > 详细

编程习惯

时间:2014-10-18 06:26:09      阅读:334      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   os   ar   使用   for   strong   

  1.   在使用多重宏嵌套定义的时候,要在#endif的后面写上注释,便于区分嵌套的关系

            #ifdef RTMP_MAC_PCI

  pDrvOps->RTMPHandleInterrupt = RTMPHandleInterrupt;

  #endif // RTMP_MAC_PCI //

     2.使用嵌套宏定义的时候,自己的习惯,只使用这一种嵌套定义的方式。

  当编译器遇到#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_disk_spindown_flag_last_timer = 0; \

                  arg.vs_usb_suspend_flag = VS_USB_SUSPEDN_DISABLE;   \

        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退回到原来的地方  原来这个功能好强啊bubuko.com,布布扣

当前在第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

当遇到一些连接的问题时,本来自己添加的头文件,想引用结果还是没有找到,可以在

bubuko.com,布布扣

解决问题的思路: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:

bubuko.com,布布扣

15、

bubuko.com,布布扣

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.进入中断拔出时,上次有卡,这次没卡,那就重新执行一次唤醒一次拔出的流程。上一次有卡,这一次没有卡,则执行如下操作。

bubuko.com,布布扣

19.C++中调用C函数代码

bubuko.com,布布扣

统一的解决方法:

__cplusplus是c++编译器内置的标准宏定义,让c代码既可以通过c编译器的编译,又可以在c++编译器中以c的方式进行编译(使用条件编译),代码如下:

  1. #ifdef __cplusplus
  2. extern "C" {  
  3. #endif
  4. // 这里面放函数的声明 或者 函数的定义
  5. int func(int a, int b)  
  6. {  
  7. return a + b;  
  8. }  
  9. int func(const char* s)  
  10. {  
  11. return strlen(s);  
  12. }  
  13. #ifdef __cplusplus
  14. }  
  15. #endif

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()

        析构函数的调用顺序是与构造函数的调用顺序完全相反的。每一个对象都有构造函数和析构函数。析构函数则需要程序员自己手写

bubuko.com,布布扣

4.静态成员变量和静态成员函数

        为了在类的多个对象之间共享变量以及简单的通知,提出了静态成员变量和静态成员函数的概念。

静态成员属于整个类所有,不需要依赖任何对象。可以通过类名直接访问public的静态成员,也可以通过对象名访问public的静态成员

静态成员函数可以直接访问静态成员变量或者全局变量。

bubuko.com,布布扣

参考网址: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这个同名函数

bubuko.com,布布扣

    查找通过函数指针调用的函数调用链条。

编程习惯

标签:style   blog   http   io   os   ar   使用   for   strong   

原文地址:http://www.cnblogs.com/cherishui/p/4032460.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!