C/C++的一些杂项
来源:互联网 发布:炉石盒子 mac 编辑:程序博客网 时间:2024/06/06 10:38
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_t
- strspn (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_t
- strcspn (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;
- }
- 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中需要注意的一些杂项
- odbc 的 c api实现简单的select*结果printf 输出
- 11Gr2RAC使用备份恢复ocr和votedisk
- STL
- 理解LSTM网络
- Hadoop YARN架构设计要点
- C/C++的一些杂项
- mac下mysql workbench导出数据库
- 同时使用Nohttp和环信出现的问题和解决方案
- MySql-如何查询删除数据表重复记录
- ReactNative动画(下)
- Android audio transmit with Base64 based on XMPP
- MFC CListCtrl的方法
- Android基础之十七使用网络技术
- Android 加载大图(一)