yanbin's Blog

vim 中使用 cscope 的方法。

0. cscope 依赖 $EDITOR, $CSCOPE_DB 环境变量。
    使用 vim 打开 cscope 的搜索结果,需要设置 $EDITOR 环境变量为 vim.
    $ vim ~/.bashrc
        # add: export EDITOR=vim
    $ source ~/.bashrc
    NOTE: 很多工具都依赖 EDITOR 这个环境变量,修改这个环境变量的值时需考虑其影响范围。
 
    vim 启动时默认加载当前工作目录下的 cscope database 文件,并且与 database 建立连接。
    在 ~/.bashrc 或者类似的文件中设置 $CSCOPE_DB 环境变量,vim 启动时也会自动加载 $CSCOPE_DB
    指定路径的 database 文件,并与 database 建立连接。
    $ vim ~/.basrch
       # add: export CSCOPE_DB=/path/to/cscope_db_file
    $ source ~/.bashrc
   
    如果这个 database 文件用在系统中的所有工作目录,其中存储的文件路径应该是绝对路径,
    不然只能用在特定的工作目录了。
    如何做到这一点呢?下面 1.2 给出方法。
    
    
 1. cscope 的一些用法与 ctags 相同。
     1.0 cscope 也支持 -R 参数,在不加 -b 参数时,cscope 运行一个curses-based GUI.
         CTRL-d 退出该 GUI, 实际上也退出了 cscope.
           Find this C symbol:
           Find this global definition:
           Find functions called by this function:
           Find functions calling this function:
           Find this text string:
           Change this text string:
           Find this egrep pattern:
           Find this file:
           Find files #including this file:
           Find assignments to this symbol:
        debug 一些问题时,经常出现(a)找到某个 error message 是在哪里打印的;
        (b)某个打印 error message 并且退出程序的函数是如何实现/定义的;
        (c)某个宏定义的值是什么; (d) 包含某个头文件的其他文件;
        (e)函数的定义以及调用的地方; 诸如此类的需求,却无需关注全部代码,用这个工具非常方便。
         cscope 还支持: (f) 使用 egrep 格式搜索字符串; (g) 根据文件名 find 文件; 实在方便。
 
     1.1 cscope -R -b  直接搜索/遍历整个源码树,生成 cscope.out 数据库文件并退出程序。
         cscope.out 类似 ctags -R 生成的 tags 文件。
         内置 cscope support 的 vim 程序自动加载当前目录下的 cscope.out 文件。
         FIXME: 不支持功能的 vim 又该如何设置才能自动化的加载 cscope.out 文件?
                       可以考在 .vimrc 中添加如下代码:
                          " add any cscope database in current directory
                          if filereadable("cscope.out")
                              cs add cscope.out
                          elseif $CSCOPE_DB != ""
                              cs add $CSCOPE_DB
                          endif
 
 
     1.2 根据多个目录中文件的绝对路径生成 database 文件。
        获得所有需要的文件的绝对路径,存放在一个文件中。
        $ find /path/to/myproject -name "*.c" -o -name "*.h" > /path/to/foo/cscope.files
        $ cd /path/to/foo # 保证 foo 中没有其他文件
        $ cscope -b
          # 在 ~/.bashrc 中添加: export CSCOPE_DB=/path/to/foo/cscope.out
 
2. vim 中使用 cscope 的方法。 vim 支持短命令 :cs; cs 即 cscope 的缩写。
    2.0 :cs 命令基础用法。
      0) cscope find 操作, 支持如下选项:
             USAGE   :cs find {querytype} {name}
             0 or s: Find this C symbol
             1 or g: Find this definition
             2 or d: Find functions called by this function
             3 or c: Find functions calling this function
             4 or t: Find this text string
             6 or e: Find this egrep pattern
             7 or f: Find this file
             8 or i: Find files #including this file
         这些选项对应不同的搜索方式。
         数字用来代替字母,作为一种记忆方式,方便不同的个人习惯选择。
 
     1) find 选项使用举例。
            :cs find c vim_free
            :cs find 3  vim_free
         这两个例子都执行 Find functions calling this function;
         NOTE: 'vim_free' 和 '3' 之间有个'空格', 这种搜索方式会乎略此类‘空格’。
 
             :cscope find t initOnce
             :cscope find 4 initOnce
          这两个例子都执行: Find this text string;
          NOTE: 与其他搜索方式不同, t or 4 以及 e or 6 方式会处理字符串的前后'空格'。
          FIXEME: find t or find 4 是如何对待 ' 和 " 这两个字符的?
                          其他搜索方式又是如何对待这两个字符呢?
                          所有的搜索方式都将 ' or " 视为 name(字符串) 的一部分,
                          无论 ' or " 在字符串的开始、结尾或中间。
          NOTE: since Cscope by default parses all C header files it finds in /usr/include,
                      you can open up most standard include files with this
 
           :cscope find s oping_receive_one
            结果如下:
            Cscope tag: ping_receive_one
                # line filename / context / line
                1 445 src/liboping.c <<ping_receive_one>>
                           static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph,
                2 706 src/liboping.c <<ping_receive_all>>
                            if (ping_receive_one (obj, ptr, &nowtime) == 0)
             Type number and <Enter> (empty cancels):
 
             从左至右依次为:
             (a)搜索结果编号;(b)结果所在文件行号;(c)结果所在文件名;(d)搜索内容;(e)结果所在行文本;
              输入「结果编号」后「回车」,vim 跳转到至一行;使用 CTRL-t 回退。
              什么也不输入直接按「回车」可退出本次搜索。
              如果只搜索到一个结果,会直接跳转过去。
 
       2) vim 中使用 cscope 需要注意的一点。
           保证 ~/.vimrc 或者 /etc/vim/vimrc 以及其他 plugin 里没有这一行:
                  set cscopequickfix=s-,c-,d-,i-,t-,e-
           这样会导致使用 scscope quick window 功能,这个功能实在难用。
           执行完 :cs find s token 之类的操作,不显示结果列表窗口,而是只有一行,既不能选中,
           也不能翻页,叫人着急的想骂娘。
     
       3) 进阶用法:
          a) 更加简略的命令格式
              :cs f s foo
          b) 水平分割当前 vim 窗口显示某个搜索结果
               :scs f s foo # 前面的 s 即为 split
          c) 垂直分割当前 vim 窗口显示某个搜索结果
               :vert scs f s foo # vert 是 vim 命令
   
    2.1 使用插件, 映射 find 操作的快捷键。
          cscope 官方教程提供了 cscope_maps.vim 插件。
          将这个插件放到 /etc/viim/plugin 目录或者 ~/.vim/plugin 目录。
          0) cscope_maps.vim 提供了如下快捷方式, 直接搜索光标(cursor)所在位置的 token or text.
             <CTRL-\>s  # symbol: find all references to the token under cursor
             <CTRL-\>g  # global: find global definition(s) of the token under cursor
             <CTRL-\>c  # calls: find all calls to the function name under cursor
             <CTRL-\>t   # text: find all instances of the text under cursor
             <CTRL-\>e  # egrep: egrep search for the word under cursor
             <CTRL-\>f   # file: open the filename under cursor
             <CTRL-\>i   # includes: find files that include the filename under cursor
             <CRTL-\>d  # called: find functions that function under cursor calls
 
          1) 使用举例:
              (a) 光标移动到要搜索的 token or text;
              (b) 同时按下 CTRL 和 \ 「反斜线」键,松开后立即按下 s 键,即执行 :cs find s token 操作;
              (c) 搜索结果如同 :cs find;
        
          2) 高级用法,显示某个搜索结果而又不影响当前窗口:
              vim 提过了 split 功能,支持水平和垂直分割窗口,可以在一个新的分割窗口中显示结果。
              使用 cscope_maps.vim plugin 中提供的快捷键可以方便的做到这一点。
              (a) 使用 <CTRL-@> 代替 <CTRL-\>, 搜索方式相同而打开结果时会从一个水平窗口打开,
                    <CTRL-@> 在 vim 中用 <CTRL-spacebar>代替;
              (b) 光标移动要搜索的 token or text;
              (c) 同时按下 CTRL 和「空格」键,松开后立即按下 s 键,即执行 :cs find s token 操作;
              (d) 搜索结果等同于 :cs find, 显示某个结果时水平分割当前窗口,显示在新窗口中。   
              (e) 同样是 :cs find s token, 垂直显示结果,则是 <CTRL-@><CTRL-@>s。
                   在 vim 中需要连续两次键入 CTRL-空格,然后再按下 s 键。
 
          3) 使用 cscope_maps.vim plugin 需要注意的地方:
              cscope_maps.vim plugin 多次一举的包含了如下代码:
                          " add any cscope database in current directory
                          if filereadable("cscope.out")
                              cs add cscope.out
                          elseif $CSCOPE_DB != ""
                              cs add $CSCOPE_DB
                          endif
              这些代码可能与 vimrc 中代码相冲突,或者与 vim 内置功能相冲突,因为它们都执行了
              加载当前目录下 cscope.out 数据库操作。vim 会启动时会提示如下错误:
                   Error detected while processing /home/username/.vim/plugin/cscope_maps.vim:
                   line 45: E568: duplicate cscope database not added
                   Hit ENTER or type command to continue
              私以为直接注释掉 scsope_maps.vim plugin 中的这几行代码就好了。
              也有人说在 ~/.vimrc 里加上: set nocscopeversbose 之类的,这完全不治本嘛。

 

自签发 SSL/TLS 证书的方法以及遇到的一些问题

PKI (Public Key Infrastructure, 公开密钥基础架构)简介
0. 目的
PKI 旨在创造、管理、分配、使用、存储以及撤销数字证书
Unix/Linux 平台上常用的 PKI 软件是 openssl.
 
1. 数字证书是什么?
在密码学上视数字证书为一种身份凭证,是一种电子文件,用于证明公开密钥的所有者的身份。
数字证书文件中包含所有者的身份信息、公开密钥信息以及数字证书本身的数字签章;
数字签章用于验证证书文件内容正确无误——没有损坏或者没有被修改过——。
如果签章是正确的,而用户可以相信签署者,之后用户就知道他们可以使用这个密钥,来与密钥的拥有者进行通信。在X.509中规范了这个认证的过程与标准。①
认证过程中会包含「用 CA 的根(roo)证书验证这份数字证书是由该 CA 签发的」。
用户可以没有自己的数字证书,但是一定需要 CA 的根证书。比如:https 通信。
 
2. 谁负责创造数字证书?
CA(Certificate Authority) 负责签发数字证书。
CA 由受信任第三方担任,签发数字证书给通信双方使用;有时只签发给服务方,比如: https 通信。
这样理解或许比较简单,互联网上的数字证书签发实际上要复杂。
我们自己签发证书给自己的程序使用,不公开业务也不公开 CA root 证书,可以不用关心太多。
 
大公司的内部业务也可能足够复杂的到需要 CA,RA 之类的。参见维基百科公开密钥基础建设
 
也有 12306 或者银行这样的公司要求用户自己下载它的 CA 的 root 证书。
 
3. 证书的层级结构。
 
设置 CA 信息和签发 CA root 证书
0.修改 openssl.conf 文件里的某些域的值。
req_distingushed_name section 可以考虑修改为:
[ req_distinguished_name ]
   countryName = Country Name (2 letter code)
   countryName_default = CN
   stateOrProvinceName = State or Province Name (full name)
   stateOrProvinceName_default = ShangHai

   localityName = Locality Name (eg, city)
   localityName_default = ShangHai
   0.organizationName = Organization Name (eg, company)
   0.organizationName_default = My Company Name

   organizationalUnitName = Organizational Unit Name (eg, section)
   organizationalUnitName_default = May Project

1. 生成 CA root key (根密钥); CA root key 非常重要。
a) 不仅签发或更新 CA root 证书需要。
b) 签发通信双方数字证书时也需要。

Create the keypair:
$ openssl genrsa -des3 -out root-ca.key 1024
 

0) 指定了 -des3 选项,openssl 要求输入 pass phrase;
pass phraseroot key 的密码;
CA 签发数字证书时需要输入这个密码,算是一种防范措施吧。

1) FIXME: 这种密码也可以用到普通证书的 key,
程序使用证书和 key 时, 一般会要求输入密码,可以作为用户密码用吗?

2) FIXME: 1024 是 key  的长度目前也支持 2048, 这两个值有很大的区别吗?

key 的长度为 2048 会耗费更多的 CPU 资源吧。

2. 自签发 CA 根证书(root certificat)
Use the key to sign itself:
$ openssl req -new -x509 -days 3650 -key root-ca.key -out root-ca.crt  -config openssl.cnf
0) 关键参数是 -x509:
生成的 root-ca.crt 是一个 self-signed X.509 certificate;

1) 这条命令将两个步骤合二为一。
a) 使用 private key 生成 certificate request; 需要填写证书持有者的信息;
b) 使用 certificate request 签发证书(singed)或自签发证书(self-signed);

2) 这个自签发证书为什么能做为 CA root certificate 使用?
因为指定了参数 -x509, openssl 配置文件 req section 指定了 x509_extensions = v3_ca;
而 v3_ca section 里则有:basicConstraints = CA:true
 
3) openssl.cnf 以及 CA directory 都不是系统中唯一存在的;
任意创建一个目录,创建配置文件(比如: openssl.cnf),也可以签发根证书。
$ mkdir demoCA && cd demoCA
$ touch index.txt
$ echo 01 > serial
$ mkdir private #指定 private_key=/path/to/demoCA/myCA/private/root-ca.key
$ mkdir myCA # 指定 CA_default:dir=/path/to/demoCA/myCA
 
4) 可以使用如下命令查看 root-ca.crt 的信息
$ openssl x509 -noout -text -in root-ca.crt

 

签发服务器证书
0.生成一个 private key, 并且直接用新生成 private key 创建一个 certificate request.
NOTE: -nodes 参数,使用这个参数生成的 key 不需要密码

$ openssl req -newkey rsa:1024 -keyout server01.key -nodes -config openssl.cnf -out server01.req

Country Name (2 letter code) [CN]:
State or Province Name (full name) [ShangHai]:
Locality Name (eg, city) [ShangHai]:
Organization Name (eg, company) [My Company Name]:
Second Organization Name (eg, company) [My Company Name]:
Organizational Unit Name (eg, section) [My Project]: 
Common Name (eg, YOUR name) []:*.example.com #CN
Email Address []:server01@example.com

NOTE: CN(common name) 可以是 hostname,IP 或者 domain, 与主机信息对应;
      也可以用这种形式: *.example.com
      CN 指的是  common name, 别与中国的代码弄混了。

 

1.使用新生成的 certificate request 签发数字证书。
$ openssl ca -config openssl.cnf -out server01.crt -infiles server01.req
# Using configuration from openssl.cnf

Enter pass phrase for /etc/pki/CA/private/root-ca.key: # 输入root key 文件的密码
DEBUG[load_index]: unique_subject = "yes"
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 2 (0x2)
Validity # FIXME: 默认是一年的有效期吗?
# 默认是 365 days 的有效期, 润年会是 366 days.
Not Before: Apr 29 15:18:20 2015 GMT
Not After : Apr 29 15:18:20 2016 GMT
Subject:
countryName = CN
stateOrProvinceName = ShangHai
localityName = ShangHai
organizationName = My Company Name
organizationName = My Company Name
organizationalUnitName = My Project
commonName = *.example.com
emailAddress = server01@example.com
.......
Certificate is to be certified until Apr 29 15:18:20 2015 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

 
签发客户端数字证书
0.为什么需要签发 client 证书?
a)client 可以用证书作为身份标识;
b)签发 client 数字证书与签发 server 数字证书相比,并没有特别的不同。
c)-nodes 不需要 key 文件有密码
 
1. 生成 client private key, 并生成 certificate request.
$ openssl req -newkey rsa:1024 -keyout client001.key -nodes3  -config openssl.cnf -out client001.req
Country Name (2 letter code) [CN]:
State or Province Name (full name) [ShangHai]:
Locality Name (eg, city) [ShangHai]:
Organization Name (eg, company) [My Company Name]:
Second Organization Name (eg, company) [My Company Name]:
Organizational Unit Name (eg, section) [My Project]: 
Common Name (eg, YOUR name) []:client001
EmailAddress []: client001@example.com
   
2. 使用新生成的 certificate request 签发证书
$ openssl ca -config openssl.cnf -out client001.crt -infiles client001.req

Enter pass phrase for /etc/pki/CA/private/root-ca.key:
DEBUG[load_index]: unique_subject = "yes"
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 2 (0x2)
Validity:
Not Before: Apr 29 15:18:20 2015 GMT
Not After : Apr 29 15:18:20 2016 GMT
Subject:
countryName = CN
stateOrProvinceName = ShangHai
localityName = ShangHai
organizationName = My Company Name
organizationName = My Company Name
organizationalUnitName = My Project
commonName = client001
emailAddress = client001@example.com
.......
Certificate is to be certified until Apr 29 15:18:20 2015 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
 
需要注意的几个问题
拖延症来袭,明天再更新

参考:
 

 

Regex Unicode 笔记

 
1. Unicode 字符集使用一个或多个 code point 代表一个字符或者说字符映射到特定的数字上。
    
2. 字符又分为基本字符和组合字符。
   一个基本字符与一个或多个组合字符构成组合序列,用来表示一些非ASCII特殊字符。
   比如:
   à 这样的音标符号, 表示为 U+0061 (a) + U+0300 (`) 这两个字符的组合;其中 a 是基本字符,
   ` 是组合字符。
 
3. 一个字符可以被多个代码点表示.
   à 即可表示为: U+0061 和 U+0300 的组合; 为了与 Latin-1 转化方便, à 也表示为 U+00E0,
   很可能是法语单词。也就是说 Unicode 代码点与字符间不是一一映射的关系。
 
4. 考虑三个问题:
   1)程序中的字符串在程序运行时,最终的数据是什么?
     用户不用考虑这样的问题,如果程序支持 Unicode 的话,字符串总是会转化为
     Unicode code point 数字存储, 无论其原来的编码是什么。
     这与编辑器是有关系的,程序中的字符串是用编辑器输入并存储的,无论程序是在编译时还是
     运行时转换这些字符串为 Unicode, 总是读入特定编码的字符串,然后解码为 Unicode,
     关键是如果判定这些字符串的编码的呢?
 
   2)程序运行时从标准输入读到字符串,最终的数据是什么?
     这个首先与程序从那里读入有关,终端吗?那就是要看终端使用的字符集(编码)是什么了,
     这影响终端的输入和打印。
     不同的终端可能不同,当然可以配置,比如:gnome-Timinal Timinitor, konsole;
     就算是从控制台对入字符串,控制台也是可以配置字符编码的。
 
   3)程序运行时从文件读到字符串,最终的数据又是什么呢?
     这个当然与文件的内容有关,与用什么编辑器编辑的文件有关,与文件的内容是如何填充的有关,
     关键是一个程序是如何识别编码的?
     上面三个问题至少可以明白一件事:
     在支持 Unicode 的程序中,要用正则表达式处理 Unicode 格式的字符串。
    
5. Unicode 组合字符序列的匹配. \X
   这个相当于' . ', dot, 用来匹配任意 Unicode 字符,包括换行符和终结符。
   在 Perl, PHP 中 \X 缩略表示 \P{M}\p{M}*, 匹配一个基本字符(除p{M} 之外的任何字符),
   之后可能有任意数目的组合字符(除\p{M} 之外), \p{M},\p{Mark} 是 Unicode 的一个属性分类,
   正是组合字符所属分类.

类型安全的 max(), min()

类型安全的 max(), min();
#define max(a, b) \
          ({ __typeof__ (a) (_a) = (a); \
             __typeof__ (b) (_b) = (b); \
             _a > _b ? _a : _b; })
#define min(a, b) \
         ({ __typeof__ (a) (_a) = (a); \
            __typeof__ (b) (_b) = (b); \
           _a < _b ? _a : _b; })
AISN C 使用 __typeof__ , GUN C 可以使用 typeof.

 

valgrind 简单使用

valgrind 是一款 memorycheck 工具,用于 c/c++ 程序的内存检查/调试。
0. 为了使用 valgrind 编译程序时要使用 gcc 的 -g 编译选项,链接libc 的 debug 版本,
   自动链接,但是要求有, 如果没有 valgrind 不能正常启动内存检查.
   程序用到的其他 C 库也要有 debug 版本的。
   也可以使用 gcc 的 -O0 编译选项。据说使用了更好。(大写 O, 数字 0)

   -g 是表示编译出的二进制代码中包含调试符号

   -O0 是 gcc 的默认选项。可能一些低版本的 gcc 需要加上这个选项。

1. Memorycheck 是 valgrind 的默认工具,--leak-check 选项可以打开 valgrind 详细的 memory leak 探测工具。
$ gcc -O0 -g example.c -o example
$ valgrind --leack-check=yes ./example arg1 arg2

 

2. valgrind 的输出。
下面是一个正常分配并正常释放内存的程序用 valgrind 调试的输出:
 
# 733 是 process id, 无关紧要;
==733== Memcheck, a memory error detector
==733== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==733== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright
info
# 以下是重要信息;
==733== Command: ./mkdir_t 1/2/3/4
==733== 
# 这里可能会有程序的 stdout/stderr 输出;
==733== 
# 内存使用状况的汇总;
==733== HEAP SUMMARY:
==733== in use at exit: 0 bytes in 0 blocks
==733== total heap usage: 3 allocs, 3 frees, 18 bytes allocated
==733== 
==733== All heap blocks were freed -- no leaks are possible
==733== 
# 错误信息汇总;(这里没有错误)
==733== For counts of detected and suppressed errors, rerun with: -v
==733== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

 


下面是一个越界使用了动态分配的内存, 没有释放动态分配内存的程序的输出;
程序名字是 example, 程序文件名后面的数字说明了 memory allocated 之类的操作的
代码在文件中的位置, 或者说哪里有 memory allocated.

 

# Invalid write 指示了 memory overrun;
==1058== Invalid write of size 4
# 这里是堆栈跟踪(stack tracking), stack tracking 从下到上读比较容易;
==1058== at 0x40054A: func (example.c:15)
==1058== by 0x400524: main (example.c:8)
==1058== Address 0x51bc068 is 0 bytes after a block of size 40 alloc'd

 

# 这里也是 stack tracking 信息,比上面的更深了一层,
# 已经到了 malloc 是内存分配的情况;
==1058== at 0x4C29554: malloc (vg_replace_malloc.c:298)
==1058== by 0x40053D: func (example.c:14) # 后面的数字指示了代码所在行
==1058== by 0x400524: main (example.c:8)
==1058== 
==1058== 
# 内存(HEAP),使用汇总;
==1058== HEAP SUMMARY:
==1058== in use at exit: 40 bytes in 1 blocks
# N allocs, N frees 才正常, 40 bytes allocated 指示分配了多少字节内存;
==1058== total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==1058== 
# definitely lost 指示了内存泄漏(memory leak);
==1058== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1058== at 0x4C29554: malloc (vg_replace_malloc.c:298)
==1058== by 0x40053D: func (example.c:14)
==1058== by 0x400524: main (example.c:8)
==1058== 
# memory leak 汇总;
# definitely, indirectly, possibly 是三种 memory leadk 方式.
==1058== LEAK SUMMARY:
==1058== definitely lost: 40 bytes in 1 blocks # 明确地
==1058== indirectly lost: 0 bytes in 0 blocks # 间接地
==1058== possibly lost: 0 bytes in 0 blocks # 可能性很大地
==1058== still reachable: 0 bytes in 0 blocks
==1058== suppressed: 0 bytes in 0 blocks
==1058== 
# 错误信息汇总
==1058== For counts of detected and suppressed errors, rerun with: -v
==1058== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)

 

3. If the stack trace is not big enough, use the --num-callers option to
make it bigger.

 

4. valgrind 也报告"使用了未初始化变量错误(uninitialished value)"的情况。
使用 --track-origins=yes 可以看到有关于此的更多的扩展信息,
但是这样也会让程序变得更慢.

 

5. Memcheck cannot detect every memory error your program has.
For example, it can't detect out-of-range reads or writes to arrays 
that are allocated statically or on the stack.
But it should detect many errors that could crash your program 
(eg. cause a segmentation fault).
 
6. 使用 valgrind 调试使用了 GLib 的程序需要加一些 flag.
    比如让 GLib 使用 std malloc.

 

 

使用 strtok() 函數要注意,這個函數會改變第一個參數的內容

char *strtok(char *str, const char *delim);
token = strtok(str, "\t "); # 算是安裝要操作的 string; str 指向這個 string;
while (token != NULL) 
    token = strtok(NULL, "\t "); # 每次操作都會改變第一此安裝的 string 的內容.
 
0. 第一次安裝後,delim 是可以改變的。
 
1. 如果在調用 strtok() 後還要正常使用 string 以及她的內容,應該在調用 strtok() 前,
    調用 strdup() 複製一份 string 的內容;
    用複製的 string 註冊 strtok();
    char *dupstr = strdup(str);
    token = strtok(dupstr, "\t ");
    //...
    free(dupstr);  // str 指向的內容還在。

伪随机数函数 rand(); srand() 的简单实现


	
 
static unsigned long next = 1;
static unsigned long myrand(void)
{
    next = next * 1103515245 + 12345;
    return ((unsigned)(next/65536) % 32768);
}

static void mysrand(unsigned long speed)
{
    next = speed;
}

/* example */
int main(int argc, char **argv)
{
    int j, r, nloops;
    unsigned long speed;

     if (argc < 2) {
         fprintf(stderr, "usage: %s <speed> <nloops>\n", argv[0]);
         exit(EXIT_FAILURE);
     }

     speed = strtol(argv[1], NULL, 10);
     nloops = atoi(argv[2]);
     
      mysrand(speed);
      for (j = 0; j < nloops; ++j) {
         r = myrand();
         fprintf(stderr, "%lu\n", r);
     }

     exit(EXIT_SUCCESS);
} 
 
 
 
 

 

bash 中的 -n 操作符判断某个变量为空时应该加上引号("")

bash 中的 -n 操作符判断某个变量为空时应该加上引号("")
不然一个为空的变量也会返回 TRUE.
e.g.
# [ -n $a ] 总是返回 TRUE
a=""
if [ -n $a ]; then
   echo "hello" # 永远会执行这里
fi
$ hello
 
# [ -n "$a" ] 当 a 为 empty 时返回 FALSE
a=""
if [ -n "$a" ]; then
   echo "hello" # 不会执行这里
fi

比 alarm() 分辨率更高的 timer: setitimer()

getitimer, setitimer - get or set value of an interval timer
 
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
 
seitimer() 设置三個 process 的内部定时器中的某一個, getitimer() 获得这三個定时器中某一個信息。
每一个 process 都有三个不同类型的定时器,which 的值对应: 
ITIMER_REAL  /* 运行在 real time, 定时器到期时提交  SIGALRM 信号 和 alarm()
                           * 提交给进程的是同一个信号。
                          */
ITIMER_VIRTUAL // 运行在 process 运行时,定时器到期时提交 SIGVTALRM 信号
ITIMER_PROF // 运行在 process 运行或在后台运行时,定时器到期时提交 SIGPROF 信号
 
struct itimerval {
       struct timeval it_interval; /* next value */
       struct timeval it_value; /* current value */
};
 
struct timeval {
       time_t tv_sec; /* seconds */
       suseconds_t tv_usec; /* microseconds */
};
 
0.  設置 it_value.tv_sec > 0 || it_value.tv_usec > 0 timer 開始運行,
    並且在固定頻率減少 it_value.tv_sec 和/或 it_value.tv_usec 的值。
    可以說 it_value 是 timer 的剩餘值。
1. 當 it_value.tv_sec == 0 && it_value.tv_usec == 0 時, timer expire。
    直接設置 it_value.tv_sec == 0 && it_value.tv_usec == 0 那麼 timer expire。
    NOTE: 對 timer it_value 的檢查可能會在一定的時間之後才會到來,
               所以不能假設清空了 it_value 就會 timer expire.
2. 一個 timer period 到期時,用 it_interval 的值初始化 it_value 開始下一個週期,
    如果 it_interval.tv_sec > 0 || it_interval.tv_usec > 0 話。
    那麼用 it_interval 的值初始化 it_value 開始下一個 timer period
3. 可以同時清空 it_interval 和 it_value 可以讓 timer 停止運行。

Debian 7.6 Wheezy 安装 Intel® Wireless 7260 wifi 模块驱动和固件的方法。

Debian 7.6 Wheezy 安装 Intel® Wireless 7260 wifi 模块驱动和固件的方法。

0. 内核以及发行版 Version 信息
    Debian 7.6 Wheezy
    Linux fyp-tp 3.2.0-4-amd64 #1 SMP Debian 3.2.60-1+deb7u3 x86_64 GNU/Linux


1. 获得 PCI device numbric ID
    $ lspci -nn # 可以显示设备号和subsystem ID
    ....
   04:00.0 Network controller [0280]: Intel Corporation Device [8086:08b2](rev 6b)
   在下面的网站可以根据设备号(0x808) 和 subsystem ID(0x08b2) 查找到设备型号:
   http://pci-ids.ucw.cz/read/PC
   可知 wifi 模块的型号是: Intel Wireless 7260

2. google 可知这个 wifi 模块使用 iwlwifi wireless driver。
    这个驱动包在 Debain nofree 源中。 使用 Debian nofree 源:
    $ sudo echo '# Debian 7 "Wheezy"' >> /etc/apt/sources.list
    $ sudo echo "deb http://http.debian.net/debian/ wheezy main contribnon-free" >> /etc/apt/sources.list

   安装完驱动后,要安装相应的固件,可以在
   http://wireless.kernel.org/en/users/Drivers/iwlwifi
   找到相应的固件包, 解压后使用 root 用户安装:
   $ cp iwlwifi-*.ucode /lib/firmware

3. 但是,Debian提供的 iwlwifi 驱动模块是 3.2.60 Linux Kernel 版本的,
    并不支持 Intel Wireless 7260 这个 wifi 模块.
    iwlwifi 驱动支持 7260 wifi 模块要求: 最低 Linux Kernel 版本 3.10+.
    但是,在 Debian 升级 Linux Kernel 不是一个好的解决方案。
    好消息是:可以使用 linux kernel backports 来编译本应该运行在高版本内核的驱动, 
   编译的得到驱动可以在低版本的内核上运行, 并且支持 wifi 模块。
   "If you need to use the current driver on an older kernel, you can use
   the compat-drivers project for that. See https://backports.wiki.kernel.org/
   for more information."


4. 下载 backports-3.14-1 在 http://drvbp1.linux-foundation.org/~mcgrof/rel-html/backports/
    需要打一个 patch: http://www.mail-archive.com/backports@vger.kernel.org/msg01790.html
    配置以及安装,参考: https://backports.wiki.kernel.org/index.php/Documentation

   #可以只配置 wifi 模块的驱动:
   $ make defconfig-wifi

   #可以选择只编译 iwlwifi
   $ make menuconfig 
       [*] Wireless LAN ---> 
               Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) 

   $ make
   $ sudo make install
   $ sudo update-initramfs

5. 在 http://wireless.kernel.org/en/users/Drivers/iwlwifi 下载:
     iwlwifi-7260-ucode-22.1.7.0.tgz
     iwlwifi-7260-ucode-22.24.8.0.tgz
     iwlwifi-7260-ucode-23.214.9.0.tgz
    三个固件包并且安装到 /lib/firmware 
    如果没有安装固件的话, dmesg 信息中会有 iwlwifi-7260-7.ucode 找不到之类的信息.
    没有测试是否也需要 iwlwifi-7260-9.ucode. (我在安装 iwlwifi 驱动之前就安装了这个固件)
 




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee