C/C++的一些杂项
来源:互联网 发布:思科arp绑定mac地址 编辑:程序博客网 时间:2024/06/06 01:36
fwrite 和 fread的参数问题
有时,我们在阅读别人的代码时会看到这样的写法:
fwrite(buff, 1, 8912, fout); fread(buff, 1, 8912, fin);我就觉得奇怪,为什么不写成:
fwrite(buff, 8912, 1, fout); fread(buff, 8912, 1, fin);
感觉第二种写法会有效率一点。因为其一次就写完,而第一种需要写多次,每次只写一个字节。后来看多代码了,发现很多人都这样写的。我就觉得里面肯定有文章。用谷歌一搜,就发现已经有老外问到这个问题了。http://stackoverflow.com/questions/19410230/fread-fwrite-size-and-count 和 http://stackoverflow.com/questions/10564562/fwrite-effect-of-size-and-count-on-performance。
从回答中可以看到,第一种写完更合理一点。首先,实现fwrite和fread函数的人不是傻蛋,其不会实现为:每次只写一个字节,写8912次 。最重要的是,在第一种写法中可以知道写了/读了多少字节。特别是在读的时候,很有必要。如果是第二种写法,在读的时候,只能返回0或者1,根本就不知道究竟读了多少字节。
C++11的编译选项
C++11越来越流行了,有必要学一下C++11。这里和这里可以看到各个编译器对C++11的支持。安装了支持C++11的编译器gcc,还要加上编译选项-std=c++11。编译命令如下:
g++ -std=c++11 test.cpp -o test
如果想在Windows下使用支持C++11的Mingw,可以到这里下载。
对于Qt Creator,这个编译选项是在.pro文件添加的,添加下面内容即可:
QMAKE_CXXFLAGS += -std=c++11
strspn和strcspn函数
strspn:
对于strspn,虽然有些文章进行了一些解说,但总是难于理解。自己写一个例子验证自己的理解,但结果并非自己预测的那样。所以我这里也来解说一下strspn,不过我是直接上strspn的实现代码。我就用glibc2.19中strspn的实现代码来解说。
size_tstrspn (s, accept)const char *s;const char *accept;{const char *p;const char *a;size_t count = 0;for (p = s; *p != '\0'; ++p){for (a = accept; *a != '\0'; ++a)if (*p == *a)break;if (*a == '\0') //遍历完accept就返回return count;else++count;}return count; //遍历完s也返回}
代码里面有两个循环,分别用来遍历两个字符串。
*p是什么,*p是另外一个字符串s的一个字符。此时联合内外循环应该可以理解为:用*p从s的第一个字符开始遍历,如果在accept中能找到等于*p的字符,那么就++count, 测试s的下一个字符。如果在accept中找不的话,就直接return count。如果s的字符都能找accept中找到,那么就返回s的长度。
用一句简单的话来叙述,那就是:遍历字符串s,返回第一个只出现在s字符串的字符的下标值(在s中的下标)。
对于s=”126.com”,accept=”1234567890”,返回值为字符”.”的下标,即3
对于s=”126.com”,accept=”google.com”,返回值为字符”1”的下标,即0
strspn函数有什么用途呢?假如accept是一个删除字符集合,并且想删除字符串s前面的一些属于删除字符集合的字符。此时strspn函数返回值就是一个下标,在该下标之前的字符统统删掉。
strcspn:
函数strcspn和前面的strspn长得有点像,可以用strspn来帮助理解。下面给出它的实现代码。
size_tstrcspn (s, reject) const char *s; const char *reject;{ size_t count = 0; while (*s != '\0') if (strchr (reject, *s++) == NULL) ++count; else return count; return count;}
用一句简单的话来叙述,遍历字符串s,返回第一个既出现在s,也出现在reject字符的字符下标值(在s中的下标)。
对于s=”hao123.com”,reject=”1234567890”,返回值为字符”1”的下标,即3
跨编译器include智能指针头文件:
在tr1中,C++加入了神器share_ptr,但不同的编译器把智能指针share_ptr 放在不同的头文件中。比如VS系列编译器把它放到memory中,而gcc(包括mingw)则放到tr1/memory头文件。由于mingw编译器在使用的时候,会自动加入WIN32这个宏,所以用这个宏来跨编译器使用share_ptr是不行的了。解决方案是使用宏_MSC_VER。这个宏是用来标明VS系统编译器版本的,当然在mingw中就不会存在的。所以可以像下面那样跨编译器使用include智能指针头文件。
#ifdef _MSC_VER#include<memory>#else#include<tr1/memory>
getopt和getsubopt命令行解析函数:
有时候我们写的程序也想像Linux的一些命令一样,可以有很多参数,这时我们就需要在自己的程序里面解析这些参数。Linux提供了两个函数getopt和getsubopt可以帮助我们完成解析操作。
getopt:
先来看一下命令行参数是怎么使用的。$ps -e、$find -name main.c这两个命令都使用了命令行参数。减号-表示一个命令行参数的开始,紧挨着-的是选项。像上面的e和name就是一个选项。其中选项e是没有参数值的,而选项name是有参数值的,为main.c。有一些选项既可以有参数值,也是可以没有参数值的。上面的-name选项就必须要有参数值。
现在来看一下getopt函数的声明。
#include <unistd.h>extern char *optarg;int getopt(int argc, char * const argv[], const char *optstring);
参数argc和argv是main函数的两个参数,而参数optstring指明要在argv中查找哪些选项。假如optstring的值为"ab:c:de::",那么就说明会在argv中查找a、b、c、d、e这5个选项(不错,选项都是一个字符的)。其中b、c选项后面带有一个冒号:,说明b和c选项都要有一个参数。选项e后面有两个冒号,那么e选项既可以有参数也可以没有参数。选项a和d都没有冒号,说明这两个个选项都是没有参数的。
int main(int argc, char** argv){int opt;while( (opt = getopt(argc, argv, "ab:c:de::")) != -1 ) {switch( opt ){case 'a' : break;case 'b' : printf("parm = %s", optarg); break;case 'c' : break;case 'd' : break;case 'e' : if(optarg){printf("option e has parm\n");}break;default : //出现了不是选项的字符}}}
可以看到,getopt函数的返回值就是对应选项的ASCII值。当查找完所有的命令行参数后就返回-1。
如果一个选项是有参数的,那么全局变量optarg就会指向这个参数字符串的开始位置。从上面的代码也可以看到,如果选项e有参数,那么optarg就不等于NULL,否则就等于NULL。
getsubopt:
getsubopt函数一般是和getopt函数配合使用的,用来处理某一个选项的参数。当一个选项的参数比较复杂时,就可以使用getsubopt函数。比如命令./test -o ro,rw,name=main.c。-o表示一个选项。而后面的那些都是该选项的参数,挺复杂的。选项o有三个子选项ro、rw和name,而只有name有参数值main.c。这些子选项之间用逗号分开,不能用空格。
看完了使用,现在看一下getsubopt的原型
#include <stdlib.h>int getsubopt(char **optionp, char * const *tokens, char **valuep);
参数tokens的修饰符有点怪怪的,不管了。先看一个例子吧。
int main(int argc, char **argv){ enum { RO_OPT = 0, RW_OPT, NAME_OPT }; char *const token[] = { [RO_OPT] = "ro", [RW_OPT] = "rw", [NAME_OPT] = "name", NULL }; char *subopts;char *value;int err = 0; int opt; while ((opt = getopt(argc, argv, "aeo:")) != -1) { switch (opt) { case 'a': break; case 'e': break; case 'o': subopts = optarg;//optarg指向参数字符串的开始位置 while (*subopts != '\0' && !err) { //getsubopt会修改subopts的值 switch (getsubopt(&subopts, token, &value)) { case RO_OPT: if( value ) printf("ro parm = %s\n", value); else printf("ro\n"); break; case RW_OPT: if( value ) printf("rw parm = %s\n", value); else printf("rw\n"); break; break; case NAME_OPT: if( value ) printf("name parm = %s\n", value); else printf("name\n"); break;default:err = 1;break; } } } } return 0;}
从上面代码可以看到,要想使用getsubopt就需要使用定义一个二维字符数组。数组里面的字符串就是命令行参数里面的子选项值。如果查找到了一个子选项,那么getsubopt函数返回这个子选项在二维数组里面的下标值。而getsubopt的参数valuep则会指向对应子选项的参数值。
参考:http://man7.org/linux/man-pages/man3/getopt.3.html
http://man7.org/linux/man-pages/man3/getsubopt.3.html
typedef类型的前置声明:
如果某个结构体类型如下定义:
typedef struct CvScalar{ double val[4];}CvScalar;
那么前置声明可以写成下面的形式:
struct CvScalar;typedef struct CvScalar CvScalar;
但是,如果某个结构体在定义的时候根本就没有名字,只是用typedef声明了一个别名,如下:
typedef struct{ int width; int height;}CvSize;
此时,就无法进行前置声明了(我google了很久都没有找到能前置声明的方法。如果读者有解决方案,还请赐教)。
虽然没有办法直接进行前置声明,但我还是进行了一个可行性尝试。不确保有可移植性。
首先,这个结构体是定义在OpenCV的cv.h头文件的,并且cv.h使用宏__OPENCV_CORE_TYPES_H__防止重复包含。我就在自己的头文件里面加入
#ifndef __OPENCV_OLD_CV_H__typedef struct{ int width; int height;}CvSize;#endif
不错,就是在自己的头文件里面定义这个类型。为了避免重复定义,在对应的源文件还需要先包含OpenCV的cv.h头文件,然后才能包含自己的头文件。
数组的数组:
独立定义几个数组,为了便于对这些独立数组统一在一个循环里面访问,需要将这些独立的数组作为另外一个数组的元素。可以使用下面的方式组装。
int main(){ int a[2] = {1, 2}; int b[2] = {3, 4}; int c[2] = {5, 6}; int *d[3] = {a, b, c}; cout<<d[0][1]<<endl; int aa[2][2] = { {1, 2}, {3, 4} }; int bb[2][2] = { {5, 6}, {7, 8} }; int cc[2][2] = { {9, 10}, {11, 12} }; int (*dd[3])[2] = {aa, bb, cc}; cout<<dd[0][1][0]<<endl; return 0;}
Source Insight识别函数前面的宏定义:
最近通过Source Insight阅读libjpeg的源代码时,发现Source Insight无法识别一些函数,这些函数的共同特点是前面定义了宏函数。在Source Insight安装目录的C.tom文件中,添加该宏函数即可。比如libjpeg一些函数名前面为宏函数GLOBAL(void),那么在C.tom文件中另起一行,添加 GLOBAL(X)
- C/C++的一些杂项
- C/C++的一些杂项
- c语言,杂项
- 我的iOS开发 4-Objective-C C相关杂项
- Effective C++(九)杂项讨论
- effective C++: 9.杂项讨论
- 【linux c】杂项驱动入门
- 关于Android的一些杂项
- 一些杂项
- Effective c++(笔记) 之 杂项讨论
- <<Effective C++>>读书笔记9: 杂项讨论
- <<More Effective C++>>读书笔记6: 杂项
- C的一些问题
- C的一些问题
- C的一些总结
- 一些非常有意思的杂项资源(转)
- 一些关于树的知识杂项
- vue中需要注意的一些杂项
- 对int整型用法的一点见解
- python数据结构与算法 35 快速排序
- php实现验证码类
- [codility]CountDiv
- getHibernateTemplate().saveOrUpdate 不执行
- C/C++的一些杂项
- Java 高新技术(注解)
- [VisualStudio]_[VS实用插件集合*持续更新]
- 【BZOJ】【P1013】【JSOI2008】【球形空间产生器sphere】【题解】【高斯消元】
- sxstrace.exe 工具的解决办法
- tiny6410 蜂鸣器字符设备驱动<2>
- 跨框架弹层
- Find the median of 2 sort ed array.
- .Java的垃圾回收机制(GC)