Archive for Linux and Shell

宽字符处理函数函数与普通函数对照表

字符分类:
iswalnum()  isalnum
()  测试字符是否为数字或字母
iswalpha
()  isalpha()  测试字符是否是字母
iswcntrl
()  iscntrl()  测试字符是否是控制符
iswdigit
()  isdigit()  测试字符是否为数字
iswgraph
()  isgraph()  测试字符是否是可见字符
iswlower
()  islower()  测试字符是否是小写字符
iswprint
()  isprint()  测试字符是否是可打印字符
iswpunct
()  ispunct()  测试字符是否是标点符号
iswspace
()  isspace()  测试字符是否是空白符号
iswupper
()  isupper()  测试字符是否是大写字符
iswxdigit
()  isxdigit()  测试字符是否是十六进制的数字


大小写转换:
towlower
()  tolower()  把字符转换为小写
towupper
()  toupper()  把字符转换为大写


字符比较:
wcscoll
()  strcoll()  比较字符串


日期和时间转换:
strftime
()  根据指定的字符串格式和locale设置格式化日期和时间
wcsftime
()  根据指定的字符串格式和locale设置格式化日期和时间, 并返回宽字符串
strptime
()  根据指定格式把字符串转换为时间值, 是strftime的反过程


打印和扫描字符串:
fprintf
()  /fwprintf()  使用vararg参量的格式化输出
fscanf
()  /fwscanf()  格式化读入
printf
()  使用vararg参量的格式化输出到标准输出
scanf
()  从标准输入的格式化读入
sprintf
()  /swprintf()  根据vararg参量表格式化成字符串
sscanf
()  以字符串作格式化读入
vfprintf
()  /vfwprintf()  使用stdarg参量表格式化输出到文件
vprintf
()  使用stdarg参量表格式化输出到标准输出
vsprintf
()  /vswprintf()  格式化stdarg参量表并写到字符串


数字转换:
wcstod
()  strtod()  把宽字符的初始部分转换为双精度浮点数
wcstol
()  strtol()  把宽字符的初始部分转换为长整数
wcstoul
()  strtoul()  把宽字符的初始部分转换为无符号长整数


多字节字符和宽字符转换及操作:
mblen
()  根据locale的设置确定字符的字节数
mbstowcs
()  把多字节字符串转换为宽字符串
mbtowc
()  /btowc()  把多字节字符转换为宽字符
wcstombs
()  把宽字符串转换为多字节字符串
wctomb
()  /wctob()  把宽字符转换为多字节字符


输入和输出:
fgetwc
()  fgetc()  从流中读入一个字符并转换为宽字符
fgetws
()  fgets()  从流中读入一个字符串并转换为宽字符串
fputwc
()  fputc()  把宽字符转换为多字节字符并且输出到标准输出
fputws
()  fputs()  把宽字符串转换为多字节字符并且输出到标准输出串
getwc
()  getc()  从标准输入中读取字符, 并且转换为宽字符
getwchar
()  getchar()  从标准输入中读取字符, 并且转换为宽字符
None gets
()  使用fgetws() 
putwc
()  putc()  把宽字符转换成多字节字符并且写到标准输出
putwchar
()  putchar()  把宽字符转换成多字节字符并且写到标准输出
None puts
()  使用fputws() 
ungetwc
()  ungetc()  把一个宽字符放回到输入流中


字符串操作:
wcscat
()  strcat()  把一个字符串接到另一个字符串的尾部
wcsncat
()  strncat()  类似于wcscat()  , 而且指定粘接字符串的粘接长度.
wcschr
()  strchr()  查找子字符串的第一个位置
wcsrchr
()  strrchr()  从尾部开始查找子字符串出现的第一个位置
wcspbrk
()  strpbrk()  从一字符字符串中查找另一字符串中任何一个字符第一次出现的位置
wcswcs
()  /wcsstr()  strchr()  在一字符串中查找另一字符串第一次出现的位置
wcscspn
()  strcspn()  返回不包含第二个字符串的的初始数目
wcsspn
()  strspn()  返回包含第二个字符串的初始数目
wcscpy
()  strcpy()  拷贝字符串
wcsncpy
()  strncpy()  类似于wcscpy()  , 同时指定拷贝的数目
wcscmp
()  strcmp()  比较两个宽字符串
wcsncmp
()  strncmp()  类似于wcscmp()  , 还要指定比较字符字符串的数目
wcslen
()  strlen()  获得宽字符串的数目
wcstok
()  strtok()  根据标示符把宽字符串分解成一系列字符串
wcswidth
()  None 获得宽字符串的宽度
wcwidth
()  None 获得宽字符的宽度


另外还有对应于memory操作的 wmemcpy
()  , wmemchr()  , wmemcmp()  ,wmemmove()  , wmemset() 

Comments (2)

浅谈C中的wprintf和宽字符显示

(转自http://blog.csdn.net/lovekatherine/archive/2007/11/06/1868724.aspx)

——————————————————

Cyndi: 先补两句,在按照下面的测试代码验证时,仍然遇到了问题.

首先,L”中文”这种通过L来转换成unicode的方式不是万能的,我试了几台linux终端都不支持这个方式,因为标准C对于L的解释是能转换ASIC,这一点因系统而宜.事实上windows是支持非ASIC字符的.

其次,printf+%ls与wprintf+%ls在我试的几台linux终端上表现是不一样的,printf+%ls可以成功输出中文,但wprintf+%ls却死活也不行,具体原因不详,(类似的,windows上测试这两个的输出结果是相同的).

最后,clocale这个头文件在windows下编译成功,但在linux下改成locale.h才编译通过.而setlocale这个函数的第二个参数在windows下用了chs,而linux下我用了zh-CN.这一点可用locale -a查询该平台支持的集合.

——————————————————

今天在CSDN的Blog首页看到一篇文章“也谈计算机字符编码 ”,由于前一阵业余翻译了“UTF-8 and Unicode FAQ for Unix/Linux”一文,自己对字符集、编码和Unicode等内容一直保着者很强的兴趣,自然不会放过这样的文章。

作者的文章写得很明白易懂,虽然有一些概念上的细节问题我觉得有商榷之处;作者还给出一个简单的在windows下使用wprintf正确输出字符串“中文”的小例子,我linux下模仿作者给出的示例代码写了如下的示例代码:

#include <cstdio>
#include
<cstdlib>
#include
<clocale>
#include
<cwchar>

int main(int argc, char * argv[])
{
wchar_t wstr[]
= L中文;
setlocale(LC_ALL,
zh_CN.UTF-8);
wprintf(L%s\n,wstr);

return 0;
}

这里需要说明的是我的机器的locale为”zh_CN-UTF-8″

然而程序的运行结果却让我很诧异

whodare@whodare:$ ./a.out
-N

我的第一反应就是作者的示例代码是不是有问题,毕竟这里面调用的全都是C的标准库函数,不应该存在移植性问题;然而,我找了台windows机器测试作者的代码,结果让我很郁闷,一切正常……

为什么我在Linux下的程序就不对呢?我很不服气,于是开始以各种关键字进行搜索,想看看别人是否遇到过类似的问题。一个搜索结果引起了我的主意,有人说问题出在wprintf中的格式转换符上,将%s替换成%ls就没有这样的问题。带着几分怀疑,我修改了上面的程序,编译运行后,居然真的就没问题了

#include <cstdio>
#include
<cstdlib>
#include
<clocale>
#include
<cwchar>

int main(int argc, char * argv[])
{
wchar_t wstr[]
= L中文;
setlocale(LC_ALL,
zh_CN.UTF-8);
wprintf(L
%s ,wstr);
wprintf(L
%ls ,wstr);

return 0;
}

上述代码的运行结果

whodare@whodare:$ ./a.out
-N
中文

问题解决了,可我还是感到迷茫:格式转换符”ls”和“s”的区别是什么?为什么原来的程序会出问题?“-N”这个字符串是怎么冒出来的?为什么作者在windows下的程序就不存在该问题?

这么多的疑惑堵在心口,我哪能心安呢。知其然还要知其所以然嘛!花了一个下午的时间仔细读了下wprintf的manual,并在gdb的帮助下做了各种试验,终于算是把我的疑惑基本都解决了。

一、以下的所有试验都是以“中文”为例,因此有必要先把它的Unicdoe码值、UTF-8编码都列出来,以便于更好的理解下文

‘中’ Unicode码值:U+4E2D UTF-8 编码 e4 b8 ad
‘文’ Unicode码值:U+6587 UTF-8 编码 e6 96 87

二、我们需要理解用char[ ]和wchar_t [ ]来存放“中文”时有什么不同

char str[]=中文;
wchar_t wstr[]
= L中文;

我们使用gdb这个强大的工具来查看str[]和wst[]中究竟都存放了哪些值(请注意颜色之间的对应关系)

(gdb) x /8xb &str
0xbf83decd: 0xe4 0xb8 0xad 0xe6 0×96 0×87 0×00 0xf0
(gdb) x
/12xb &wstr
0xbf83dec0: 0×2d 0×4e 0×00 0×00 0×87 0×65 0×00 0×00
0xbf83dec8: 0×00 0×00 0×00 0×00

不难看出,char str[ ]中存储的是“中文”的UTF-8编码,这是因为我的机器的locale是zh_CN.UTF-8,程序源文件的自然采用的是UTF-8编码,因此编译器在处理 char str[ ]=”中文”; 时,t它对str[]所做得初始化实际上可以理解成 char str[ ]={ 0xe4,0xb8,0xad,0xe6,0×96,0×87,0×00}

而wchar_t wstr[ ]中存放的是“中文”的Unicode码值,这符合C标准对宽字符的定义。这里需要解释的是C标准中规定宽字符是16 bit的字符,而从GNU glibc 2.2开始,类型wchar_t只用于存放32-bit的ISO 10646码值(你可以粗略的把ISO 10646理解成Unicode,尽管它们并不是一回事),而独立于当前使用的locale;因此在上面的输出中,我们看到每个Unicode码值用 32bit表示,而不是16bit。

三、关于%s和%ls的区别

我搜到了一篇帖子(很伤感,我再此发现在CS领域,最靠的住的资料总是英文的),里面对各种格式转换符有详细的解释,愿意看原文的同学直接忽略本段文字…….

http://www-ccs.ucsd.edu/c/lib_prin.html

首先,%ls和%s的区别很简单,%ls意味着将对应的参数会被当作基于宽字符的字符串(wide chraracter string )看待,而%s则意味着对应的参数会被当作普通字符串(multi-byte string)看待。

其次,不要因为上面一句话而错误的认为%s只用于printf,而%ls只用于wprintf 。实际上,(printf, wprintf) 和(%s,%ls)这两个元组之间是相互独立的,也就是说它们之间的四种组合都是可以的。

再次,printf用于byte stream,即输出流中的每个字符颤1 byte;而wprintf则用于wide stream,输出流中的每个字符不止 1 byte。

说了一堆废话,还是结合实例来看看%ls和%s的区别吧

例子1 printf + %s + wstr

printf(%s ,wstr);

whodare@whodare:$ .
/a.out
-N

哈,这个郁闷的”-N”又一次出现!为什么会出现呢?让我来分析一下printf在执行时所完成的操作吧。

这里用了%s, printf 就会将对应的参数wstr视为普通字符串(尽管我们清楚他是个wcs而不是mbs);另一方面,我们已经看到了wstr[ ]的内存布局,其前3 byte为 0×2d ,0×4e,0×00。我们都知道C中的字符串以’\0′为结束标志,因此printf只会处理wstr[ ]中的前三个byte,而查一查ASCII表,0×2d对应字符’-',0×4e对应字符’N',所以我们会看到”-N”这个诡异的输出。

例子2 printf + %ls + wstr

printf(%ls ,wstr);

whodare@whodare:$ .
/a.out
中文

使用了%ls,printf会将对应的参数视为宽字符串(wcs),而printf又对应byte stream,因此这里要对宽字符(wcs)进行转换,变成普通的字符串(mbs)。这里的转换是printf通过对每个宽字符隐式的调用wcrtomb ()这个标准库函数完成的。按么,wcrtomb()这个函数进行是按照什么规则进行转换的?这就是setlocale()的作用所在了,wcrtomb 会依据程序员设定的locale,将wcha_t中存放的码值,转换为相应的的多字节编码。

回到例子中,我的机器的locale为zh_CN.UTF-8,对应的编码为UTF-8,因此wstr[ ]中存放的Unicode码值会转换为UTF-8编码的形式输出到标准输出流中,这样采用UTF-8编码的console就能正确识别受到的字节流并显示出”中文”

例子3 wprintf + %s +wstr (最初的代码!)

wprintf(L%s ,wstr);

whodare@whodare:$ .
/a.out
-N

使用了%s,wprintf会将对应的参数视为普通字符串mbs,尽管我们还是很清楚它其实是个wcs。wprintf 使用的是wide stream,因此需要将所给的mbs参数转换为wcs再由wprintf完成输出;这个转换是由wprintf隐式的对mbs不断调用mbrtowc来完成,转换规则依然是和locale相关的。

我们知道wstr的内存布局为:
0×2d 0×4e 0×00 0×00
0×87 0×65 0×00 0×00
0×00 0×00 0×00 0×00
该”mbs”的转换结果为 L‘0×2d’ + L ‘0×4e’ + L ‘0×00′ ,最终输出结果又是讨厌的”-N”

该”mbs”的转换结果为 L‘0×2d’ + L ‘0×4e’ + L ‘0×00′ ,最终输出结果又是讨厌的”-N”例子4 wprintf + %ls+ wstr

wprintf(L%ls ,wstr);

whodare@whodare:$ .
/a.out
中文

使用了%ls,wprintf会将对应参数视为宽字符串wcs,这次终于没有搞错。因此wprintf会顺利的将给定的宽字符串写入标准输出流,最终正确显示”中文”

看完这4个例子,你对wprintf、printf和%ls 、%s的使用还有疑惑么?

四、小结

1。要清楚%ls和%s的意义在于指明所期待的参数是何种字符串,而printf和wprintf的区别在于所使用的是不同类型的stream

2。貌似在linux下输出“中文”的正确方法是 wprintf( “%ls\n”,L”中文”) ,而引文中作者在Windows成功操作的wprintf(”%s\n”, L”中文”)在linux无法正确工作,至于为何wprintf这个标准库函数在两个系统下有不同表现,我是无心再向下深挖了,难道这又是VC一处不符合标准的地方?…….

3 。貌似还有一个%S,单独用于表示对应参数是宽字符串

谁能告诉我该问题的答案,不盛感激…….

Comments (5)

Tcpdump的使用

Tcpdump是个好东西,它可以跟踪tcp/ip通信中的每次包与包的交互过程,可以直接的从底层看到数据包的内容,而去除掉了应用层叠加的一些处理顺序等问题,简单地说说它怎么使用吧.

1.编译一个arm下的tcpdump,放到板子上.

2.先在板子上拔号,以获得可绑定的IP地址,比如打开邮件应用进行接收,当拔号结束后就可以启动tcpdump了.

3.tcpdump -w -s 1024 filename    //-s 1024的意思是取每个包的前1024个字节.默认好像是64.

4.当抓包结束后,将通过tcpdump分析filename文件的内容,这个过程也可以放到linux pc上进行,在板子上分析速度太慢.

5.tcpdump -X -r filename > filename2     //-X的意思是以二进制的方法分析.

6.取一段filename2的内容如下.(to be continued)

Comments

autoexpect工具和scp命令

昨天从同事那里学到一个很有用的工具,linux典型安装中会自带该工具autoexpect.

假设你需要登录到一个远程服务器上,执行一些脚本,这个过程即可通过autoexpect工具进行自动记录并且变成一个脚本.

在我平常打包时需要做几件事情,从48服务器(A)传几个文件到45服务器(B)上,然后登录到45服务器(B)执行几个shell脚本,然后再从45服务器上telnet到191服务器(C)上,在191上再执行几个shell脚本,回到45之后再将几个文件传回到48.

简而言之,即从A传文件到B—>登录B—>执行几个B上的命令—>登录C—>执行几个C上的命令—>从B传文件到A上—>Over.

下面说明如何使用autoexpect使这个过程自动化:

#autoexpect -f auto ssh B

执行这个命令后,auexexpect工具会提示你输入登录密码,同时开始记录从此之后的所有操作,直到你退出A服务器,因此我从B上向A索取文件,再在B上执行所需的命令,再telnet到C上执行脚本,最后再从B上把文件发送给A,这些过程都将被记录到auto这个脚本文件中.

今后,我只需要在A上执行expect auto这个命令即可轻松的等待它自动化完成上述工作啦~:)

PS:

在A服务器上传输文件到B时可以使用scp filename username@B:/home/public/

这句话的意思是,将A服务器上当前目录下的filename文件传输到B服务器的/home/public目录下.

PS:不过autoexpect是通过明文保存服务器的登录密码的,有需要的人可以了解一下如果对密码加密.

Comments (31)