c 和c ++总结

1.   0X0

0x0地址是NULL

 

2.   Gdb调试子进程

1.set follow-fork-mode  

这条命令可以用于在调试父进程或是子进程的模式之间进行切换。例如在fork函数执行之前执行set follow-fork-mode child, fork执行后,设定在子进程上的断点将会有效,而父进程上的断点此时无效;反之依然。缺省gdb是调试主进程的。

 

2.attach

GDB有附着(attach)到正在运行的进程的功能,即attach 命令。因此我们可以利用该命令attach到子进程然后进行调试。

 

3.   Gdb调试nginx

多进程调试

#sudo gdb –q

(gdb)shell ./nginx

 

如果只是gdb ./nginx

那么启动nginx还是单进程

 

 

4.   Linux内核模块编写和makeFile编写

hello.c内容:

#include

#include

static int hello_init(void)

{

        printk( KERN_ALERT " hello world enter \n");

        return 0;

}

static void hello_exit(void)

{

        printk(KERN_ALERT " hello world exit  \n");

}

module_init(hello_init);

module_exit(hello_exit);

 

MakeFile编写:

KERNEL_VERSION=/lib/modules/$(shell uname -r)/build

PWD=$(shell pwd)

default:

        make -C $(KERNEL_VERSION) M=$(PWD) modules

注意上面的make –C需要时半角,而且前面需要有一个TAB,否则会执行失败

 

  一、模块加载函数:  (必须)

  module_init(initialization_funciton);

  二、模块卸载函数:   (必须)

  module_exit(cleanup_function);

  三、模块参数:

  module_param(参数名,参数类型,参数读/写权限)

  在模块插入时: insmod   模块名   参数名=参数值

  eg:

  static char *book_name = " Linux 设备驱动 ";

  static  int num = 4000;

  module_param(num, int , S_IRUGO);

  module_param(book_neme ,charp, S_IRUGO);

  参数类型:  byte, short, ushort, int uint, long , ulong, charp(字符指针), bool,

  四、导出符号   (建议有)

  EXPORT_SYMBOL( 符号名/函数名)

  EXPORT_SYMBOL_GPL(符号名 /函数命)

  五、模块声明

  MODULE_LICENSE(" Dual BSD/GPL ");

  MODULE_AUTHOR (" XXXXX");

  MODULE_DESCRIPTION("XXXXX DRIVER");

  MODULE_VERSION(" XXXX VERSION");

  MODULE_DEVICE_TABLE(TABLE_INFO);

  MODULE_ALISA(XXXXXXX);

 

5.   内核编程中的EXPORT_SYMBOL

EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用  您还可以手工修改内核源代码来导出另外的函数,用于重新编译并加载新内核后的测试。

使用时注意事项:
在使用EXPORT_SYMBOL .c文件中 需要 #include  文件。
// 
先写函数
func_a ()
{

}
//
再使用EXPORT_SYMBOL
EXPORT_SYMBOL(func_a); 

注:export出的函数必须为非static函数,且要在相应的.h文件中进行声明。 
      
在内核中新加入文件时,需要对相应目录下的Makefile进行更改,并且新加入的文件使用的config设置与调用函数文件的config设置同。\\

 

6.   Sprintf和printf的区别

Sprintf是将一个格式化后的字符串输出到指定的字符串中;

Printf是将格式化后的字符串输出到屏幕中

 

 

7.   宏和函数在同名在一个头或者一个文件的作用

当宏和函数同名在一个文件中时,那么函数将被宏替换掉,执行宏的内容,因为宏在预编译时已经将内容替换。

一般这种写法都是用作注释函数的作用。

例子:

#include "stdio.h"

void p(int a,int b,int c){

   printf("%s","test");

}

#define p(a,b,c)({(void)b,NULL;printf("%s","aaaa");})

int main(){

   p(1,2,3);

   printf("%s","hello world`");

}

 

上面代码执行后,输出的是aaaahello world

 

 

8.   结构体赋值并初始化

//结构体定义:

struct testa{

  int a;

};

//结构体赋值

struct testa sa={

   .a=1

};

 

 

9.   Gdb 加参数调试

首先进入GDB,然后设置断点

然后用set args 参数1 参数2 ….

然后执行r则可以进入到断点中了

 

 

10.         Strdup 复制字符串

原型:extern char *strdup(char *s);

  头文件:#include

  用法:char *strdup(char *s);

  功能:复制字符串s

说明:strdup()在内部调用了malloc()为变量分配内存,当程序结束后,必须用free()释放相应的内存空间,否则会造成内存泄漏

#include

  #include

  int main()

  {

  char *s="Golden Global View";

  char *d;

  clrscr();

  d=strdup(s);

  printf("%s",d);

  free(d);

  getchar();

return 0;

}

 

执行后输出Golden Global View,就是把s 的内容复制给了d

 

11.        atoi 字符串转换为整数函数

功 能: 把字符串转换成整型数.

  名字来源:array to integer 的缩写.

  原型: int atoi(const char *nptr);

函数说明: 参数nptr字符串,如果第一个非空格字符不存在或者不是数字也不是正负号则返回零,否则开始做类型转换,之后检测到非数字(包括结束符 \0) 字符时停止转换,返回整型数。

12.         Gdb 显示函数调用栈

打好断点后,执行后,执行bt命令则显示出函数的调用栈信息:

 

 

13.         gdb "value optimized out"原因

 是因为在编译时加入了编译优化参数,比如gcc -O2,导致变量在调试中不能读出。将编译参数-O去掉即可。.configure

 

14.     strchr

 原型:extern char *strchr(const char *s,char c);

  const char *strchr(const char* _Str,int _Val)

  char *strchr(char* _Str,int _Ch)

  头文件:#include

  功能:查找字符串s中首次出现字符c的位置

  说明:返回首次出现c的位置的指针,如果s中不存在c则返回NULL。

返回值:Returns the address of the first occurrence of the character in the string if successful, or NULL otherwise

 

15.     strtod

 strtod(将字符串转换成浮点数)

  相关函数

  atoi,atol,strtod,strtol,strtoul

  表头文件

  #include<stdlib.h>

  定义函数

  double strtod(const char *nptr,char **endptr);

  函数说明

  strtod()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,到出现非数字或字符串结束时('\0')才结束转换,并将结果返回。若endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr传回。参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分。如123.456或123e-2。

 

 

16.     Floor

函数名: floor

  功 能: 返回小于或者等于指定表达式的最大整数

  用 法: double floor(double x);

  头文件:math.h

 

17.     Fprintf

  #include <stdio.h>

  int fprintf( FILE *stream, const char *format, ... );

  fprintf()函数根据指定的format(格式)(格式)发送信息(参数)到由stream(流)指定的文件. fprintf()只能和printf()一样工作. fprintf()的返回值是输出的字符数,发生错误时返回一个负值.

返回值:

若成功则返回输出字符数,若输出出错则返回负值。

 

 

例子:

#include

int main(void)

{

FILE *stream;

if ((stream = fopen("testwrite.txt", "a")) == NULL) /* open file TEST.$$$ */

{

fprintf(stderr, "Cannot open output file.\n");

return 1;

}

s.i = 0;

s.ch = 'A';

//fwrite(&s, sizeof(s), 1, stream); /* ..struct..*/

 

int f=fprintf(stream,"%s %d\n","test aaa",123);

int fe=ferror(stream);

printf("%d %d",fe,f);

//printf("%s",f);

fclose(stream); /*....*/

return 0;

}

 

 

18.     Ferror

 函数名: ferror

功 能: 在调用各种输入输出函数(如 putc.getc.fread.fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。 它的一般调用形式为 ferror(fp);如果ferror返回值为0(假),表示未出错。如果返回一个非零值,表示出错。应该注意,对同一个文件 每一次调用输入输出函数,均产生一个新的ferror函 数值,因此,应当在调用一个输入输出函数后立即检 查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。

例子见17

 

在保障健壮性的情况下需要对文件的输出进行状态判断。

 

 

19.     C中字符指针的赋值

赋值可以通过strcpy和sprintf来进行赋值

数值型的,需要先声明一个数值类型的变量,然后把变量赋值给指针

例:

char *a=(char*)malloc(sizeof(char)*100);

  int *b=(int*)malloc(sizeof(int)*8);

  strcpy(a,"\naaaa\n");

  printf("%s",a);

  sprintf(a,"%s%d%f\n","aaabbbbccc",123,1.23);

  printf("%s",a);

  *b=10;

  int c=100;

  *b=c;

  printf("%d\n",c);

  printf("%p\n",b);

  printf("%p",c);

  free(a);

  free(b);

 

 

20.     malloc

malloc是stdlib.h库下的

 

21.     strcat

原型

  extern char *strcat(char *dest,char *src);

用法

  #include

功能

  把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。

说明

  src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

返回指向dest的指针。

 

 

22.         未声明(在此函数内第一次使用)

如果报了该错误,你声明的是外部全局变量,那么可能声明位置不对,你可以把你的变量放在文件的首部,这样就可以了。

 

 

23.         查看core_dump,然后调用堆栈

ulimit –c 是查看coredump的大小

ulimit –c 1024设置coredump大小,也可以通过unlimited设置(不限制)

ulimit –c 后面跟随的是core file size 是文件的大小,单位是kb,1024就是1m,512m就是1024*512

echo "1" > /proc/sys/kernel/core_uses_pid使core文件名加上pid号,还可以用

mkdir -p /root/corefile

echo "/root/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern控制core文件保存位置和文件名格式。

以下是参数列表:
    %p - insert pid into filename 
添加pid
    %u - insert current uid into filename 
添加当前uid
    %g - insert current gid into filename 
添加当前gid
    %s - insert signal that caused the coredump into the filename 
添加导致产生core的信号
    %t - insert UNIX time that the coredump occurred into filename 
添加core文件生成时的unix时间
    %h - insert hostname where the coredump happened into filename 
添加主机名
    %e - insert coredumping executable name into filename 
添加命令名

 

当你执行二进制文件错误时,会生成一个coredump的文件在/root/corefile/目录下,然后通过gdb [exec file] [core file] 命令查看

:
gdb ./test 
/root/corefile/core-xxx-xxx

进入gdb后通过bt查看调用堆栈

 

普通用户,首先需要设置

ulimit –c unlimited

然后设置的

echo "/export/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

这个/export/目录,用户需要有写权限,如:chmod –R 775 /export

这样用户和组都有对该目录的写权限

 

如果想永久的保存该信息,那么则需要保存在环境变量配置中,如:

/etc/profile

~/.bashrc

24.      G++编译

g++ test_mongodb.cpp -I /export/dev/usr/include/ /export/dev/usr/lib/libmongoclient.a /usr/lib64/libboost_thread-mt.so /usr/lib64/libboost_filesystem.so /usr/lib64/libboost_program_options.so -o test_mongodb

 

 

 

g++ test_mongodb.cpp -I /export/dev/usr/include/ -lmongoclient -L/export/dev/usr/lib/ -lboost_thread-mt -lboost_filesystem -lboost_program_options -L/usr/lib64/ -o test_mongodb

 

引入依赖库的库和动态链接库即可,注意路径,如/export/dev/usr/include/mongo

下面有个mongo目录,在cpp中引用的是mongo/….,那么这里就直接写include即可,如果cpp中没有写mongo 直接写的../../,那么外面编译时则需要加上/export/dev/usr/include/mongo

 

25.         error: default argument given for parameter 1 of错误解决方法

/export/dev/hiphop-php/src/runtime/ext/ext_mongo.cpp:32: error: default argument given for parameter 1 of 'HPHP::c_Mongo::c_Mongo(const HPHP::ObjectStaticCallbacks*)'

当报如上错误时,是由于函数的参数默认值在声明时已经存在,而在实现时又重新定义,所以出现这个问题,所以在头文件中声明默认值后,在cpp文件中,实现时,参数就无需要在写默认值,如:

string Money::asString(bool shortVersion=true){

}

 

在cpp中

string Money::asString(bool shortVersion){}

就不需要重新声明默认值了

 

26.         编译c++错误

/export/dev/hiphop-php/src/runtime/ext/ext_mongo.cpp:31: error: expected unqualified-id before ':' token

 

编译时出现这个错误,是在31行:

c_Mongo:c_Mongo(const ObjectStaticCallbacks *cb): ExtObjectDataFlags(cb){

 

 }

 

注意c_Mongo:c_Mongo这里,正常的c++类函数实现应该是:

c_Mongo::c_Mongo

所以31行处少了一个引号,改为2个就可以了

 

/export/dev/hiphop-php/src/runtime/ext/ext_mongo.h:36: error: 'DBClientConnection' does not name a type

 

27.         获取环境变量

 函数名: getenv

  功 能: 从环境中取字符串,获取环境变量的值

  头文件: stdlib.h

用 法:char *getenv(char *envvar);

 

28.         引用定义需要初始化

error: uninitialized reference member 'HPHP::c_Redis::c'

 

29.         报指针转换错误解决方法

/export/dev/hiphop-php/src/runtime/ext/ext_redis.cpp:36: error: cannot convert 'redis::base_client' to 'redis::client*' in assignment

当报如上错误时,可能是由于编译环境不同造成的,如:

redis::client *c;

boost::shared_ptr shared_c=boost::shared_ptr( new redis::client(host.data(),port));

c=*shared_c;

如上赋值把shared_c赋值给c会报上面的错误,所以改为如下方式:

c=&(*shared_c);

改成这样就没有问题了。

 

 

30.         Strace 查看调用函数

Strace –p 端口

31.         C拼接字符串乱码

char* varKey=(char*)malloc(varLen,1);

char* temp_varKey="mGet";

printf("%s\n",varKey);

当输出时,varKey是乱码

将分配空间语句改为:

char* varKey=(char*)calloc(varLen,1);即可

 

32.         报类型转换不匹配解决方法

error: invalid conversion from 'void*' to 'redisReply*'

当报如上错误时,是有如下语句造成的

reply = redisCommand(c,"SELECT %d",dbindex);

类型void不允许转换为'redisReply,这可能是由于编译器不同造成的,因为无法识别类别,如果我们知道类别,那么强转一下即可,如下:

reply = (redisReply*)redisCommand(c,"SELECT %d",dbindex);

这样就没有问题了,指定上'redisReply这个类型

 

33.         空指针判断和输出

通过printf输出指针

Char *a=NULL;

printf(“%p”,a);

输出如下值:

(nil)

就是空指针

判断空指针:

If(a==NULL){

 

}

 

 

34.         make: Nothing to be done for `all'解决方式

make clean

make

 

 

35.         gcc编译添加动态库

gcc test_redis_libevent.c -I  hiredis/ -I /export/dev/usr/include/ -levent -lhiredis -L/export/dev/usr/lib/ -o test_redis_libevent

-I 是添加文件夹(是ai)

-levent 这里后面连接的是名字,找libevent这个库(小L)

-L 是包的路径

 

36.         Mongo c++ limit

       
       
       
       
       
       
       
       

auto_ptr< DBClientCursor > mongo::DBClientBase::query   (        const string &        ns,

Query      query,

int   nToReturn = 0,

int   nToSkip = 0,

const BSONObj *    fieldsToReturn = 0,

int   queryOptions = 0,

int   batchSize = 0

)       

nToReturn 就是limit

 

37.         gdb list错误

(gdb) list analysis_result.cpp

Can't find member of namespace, class, struct, or union named "analysis_result.c                                                                                        pp"

这种写法有问题改为如下写法即可:

(gdb) list analysis_result.cpp:1

冒号后面是行号或者方法名称

 

 

38.         C++ std::set swap

Swap方法是交换2个集合内容

 

39.         头文件中写实现函数默认是内联

 

40.         C++的set用法

使用set需要

#include

#include

using namespace std;

后2个是必要的

 

声明一个set对象:

std::set done;

<>间是他的类型

插入内容

done.insert(“test”);

根据类型不同可以插入不同对象;

Set的find使用

std::set ::iterator test=done.find("test");

    if(test==done.end()){

        cout<<"end"<

    }else{

        cout<<"find"<

}

如果find中的内容在set内,那么则find的返回值不是set的end,否则find内查找的内容set中不存在,那么返回值与set的end是相等的。

 

 

41.         Gdb watch(观察点)使用

1 #include

  2

  3 using namespace std;

  4

  5 int main(){

  6    cout<<"test gdb"<

  7    int a=0;

  8    for(int i=0;i<10;i++){

  9         a++;

 10    }

 11    cout<

 12    return 0;

 13 }

 

在编译时:

g++ -g test_gdb.cpp –o tet_gdb

然后执行:

Gdb ./test_gdb

然后在6行打上断点

b 6

断点需要打在可以捕捉到观察点变量的位置,我们要观察的是a

然后运行程序,执行r

执行r后,进入断点

然后我们执行

Watch a

(gdb) watch a

Hardware watchpoint 2: a

这样便成功的加入了观察点,然后执行c

当观察点发生变化时:

Hardware watchpoint 2: a

 

Old value = 0

New value = 1

main () at test_gdb.cpp:8

8          for(int i=0;i<10;i++){

 

这里就进入了变化的位置

 

 

42.         __thread

线程局部变量修饰关键字,如:

__thread  int f;

 

43.         dynamic_pointer_cast 动态指针转换

boost:: dynamic_pointer_cast

这个是将指针动态向上转换,如:

Class A{

 

}

 

Class B:public A{

 

}

Int main(){

  boost::shared_ptr ptrBase = boost::shared_ptr(new B());

boost::shared_ptr ptrDerive = dynamic_cast >(ptrBase); 

return 0;

}

这样就转换成功了。

 

44.         C++ 的转换操作符

Class SmallInt{

         Public:

         SmallInt(int i=0):value(i){….}

         Operate int() constr{ return val;}

         Private:

         Std:size_t val;

}

 

C++的转换操作符的主要功能是做类型转换用途

如:

(1)只要存在转换,编译器将在可以使用内置转换的地方自动调用它:

SmallInt si;

double dval;

si >=dval;

(2)在条件中:

If(si)

(3)将实参传给函数或从函数返回值:

Int calc(int);

SmallInt si;

Int i=calc(si);

(4)作为重载操作符的操作数:

Cout

(5)显式转换:

Int ival;

SmallInt si=3.511;

Ival = static_cast(si)+3;//转换si为int

但是,这个不可以做2次类型强转,如:

Class Intergral{

         Public :

         Intergral(int i=0):val(i){}

         Operator SmallInt() const{return vale %256}

         Private:

         Std:size_t val;

}

 

Int calc(int);

Integral intVal;

SmallInt si(intVal);// intVal转换为 SmallInt

Int I =calc(si); //si转换为int

Int j =calc(intVal);// 错误,intVal不能二次转换为int

 

只能先将Integral 转换为SmallInt ,然后通过SmallInt转换为int,不能直接通过Integral转换为int,也就是转换操作符不能进行二次转换。

 

详细见:

C++ primer的455-457

 

45.         c++ 代码换行符

#define EXCEPTION_COMMON_IMPL(cls) \

  virtual cls* clone() { \

    return new cls(*this); \

  } \

  virtual void throwException() { \

    Deleter deleter(this); \

    throw *this; \

  }

 

C++中的宏需要在一行中定义,但是由时候代码过多,所以用\来进行换行标注

 

46.         C 可变参数实现

如:

int demo(char *msg, ... ) 

参见如下网页内容:

http://blog.csdn.net/weiqubo/article/details/4857567

 

47.         指针值

#include

#include

int main(){

        int *a= (int *)malloc(sizeof(int));

        int b=111;

                   //指针地址

        printf("%p-----\n",a);

                   //指针的值

        *a=b;

                   //指针值

                   printf("%d-----\n",*a);

                   //指针地址

        printf("%p-----\n",a);

        free(a);

        return 0;

}

 

输出:

0x209b010-----

111-----

0x209b010-----

 

 

48.         pthread_mutex_lock 互斥锁

pthread_mutex_lock

头文件:

  #include

函数原型:

  int pthread_mutex_lock(pthread_mutex_t *mutex);

返回值:

在成功完成之后会返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,该函数将失败并返回对应的值。

 

49.         C 断言assert使用

在c语言中使用断言可以保证其健壮性,如果在断言的位置错误的时候,程序将终止;

例子:

#include

#include

 

int main(){

        assert(1==1);

        printf("assert test!");

}

上面的是可以正常输出的,如果将

  assert(1==1);

换为

  assert(1==0);

 

报出如下错误:

test_assert: test_assert.cpp:5: int main(): Assertion `1==0' failed.

Aborted

断言失败,也就是该地方是false

断言使用的位置:

(1)空指针。

(2)输入或者输出参数的值不在预期范围内。

(3)数组的越界。

 

不适合使用断言的位置:

 断言语句不是永远会执行,可以屏蔽也可以启用

  因此:

  1.不要使用断言作为公共方法的参数检查,公共方法的参数永远都要执行

2.断言语句不可以有任何边界效应,不要使用断言语句去修改变量和改变方法的返回值.

 

50.         C++ main 方法之前加载内容

我们都知道一个C++的程序要先从main函数执行起这是基本的编程常识但是我们却可以在main函数执行之前先来执行一段代码这是利用全局变量和构造函数的特性再有全局变量的时候要先创建全局变量然后在执行main函数

 

例:

#include

static int label= 0;

 

class Test

{

  public:

        Test();

};

 

Test::Test(){

        label=11;

        printf("call Test!");

}

 

Test test;

int main(){

//      Test test;

        printf("%d--\n",label);

        return 0;

}

 

这样输出就会是:

call Test!11—

 

label已经被初始化好内容了

这是利用了构造函数初始化,构造函数加载在main之前了

 

如果把没有Test test;这行语句,那么久会输出

0—

 

51.         C语言中宏#和##的作用

http://blog.sina.com.cn/s/blog_95b655e001013jdc.html

例如下面的宏定义

#define STR( s ) #s

 

那么在程序中

printf("The string is %s/n", STR(OPEN) );

会被展开成

printf("The string is %s/n", "OPEN" );

 

也就是说,会对#后跟的参数加引号,使其变成一个字符串。

 

2. ##的作用是对文本进行连接

例如下面的宏定义

#define  CONS( a, b ) a##e##b

那程序中

printf("the number is %d/n", CONS(2,3) );

会被展开成

printf("the number is %d/n", 2e3 );

 

 

需要注意的是,在有###的宏中,如果参数本身是宏,则这个参数宏不会展开。

加一层中间转换宏可以解决这个问题。

#define _STR(s)     #s 
#define STR(s)      _STR(s)          // 
转换宏 
#define _CONS(a,b)  int(a##e##b) 
#define CONS(a,b)   _CONS(a,b)       // 
转换宏

 

 

52.         函数指针

#include

 

int testcall(int &a);

 

int main(){

  int a=3;

  //testcall(a);

  //声明函数指针

  int (*f)(int &b);

  //给函数指针赋值

  f=testcall;

  printf("%d++\n",f(a));

  printf("f address %p,testcall address %p\n",f,testcall);

  printf("%d--\n",a);

  return 0;

}

 

int testcall(int &a){

        a=a+1;

        return a;

}

 

 

输出结果:

4++

f address 0x40060f,testcall address 0x40060f

4—

 

 

53.         boost::program_options的使用

参照:

http://www.rosoo.net/a/201109/14993.html

 

 

从命令行提取程序运行时选项的方法有很多。你可以自己编写相对应的完整的解析函数,或许你有丰富的C语言编程经验,熟知getopt()函数的用法,又或许使用Python的你已经在使用optparse库来简化这一工作。

program_options 
提供程序员一种方便的命令行和配置文件进行程序选项设置的方法。使用program_options库而不是你自己动手写相关的解析代码,因为它更简单,声明程序选项的语法简洁,并且库自身也非常小。将选项值转换为适合的类型值的工作也都能自动完成。库有着完备的错误检查机制,如果自己手写解析代码时,就可能会错过对一些出错情况的检查了。最后,选项值不仅能从命令行获取,也能从配置文件,甚至于环境变量中提取,而这些选择不会增加明显的工作量。

1. 首先看一个简单的程序吧:

#include  

#include  

#include  

using namespace std; 

 

int main (int ac, char* av[]) 

    boost::program_options::options_description options("command line options"); 

    options.add_options() ("help", "Use -h or --help to list all arguments") 

        ("file", boost::program_options::value(), 

         "Provide input file name"); 

    boost::program_options::variables_map vmap; 

    boost::program_options::store( 

boost::program_options::parse_command_line(ac, av, options), vmap); 

    boost::program_options::notify(vmap); 

 

    if (vmap.count("help")) { 

        cout << options << endl; 

    } 

 

    if (vmap.count("file")){ 

        cout <<"Your input file: " << vmap["file"].as() << "\n"; 

    } 

 

    return 0; 

 

//compile: g++ boost_test.cpp -o boost_test -lboost_program_options 

程序的工作方式如下:
    options_description 
类声明所有的有效命令行选项。
    
使用方法 add_options,您可以注册命令和跟在命令后面的参数类型。在此例中,help 选项不需要任何参数,但是 file 选项需要一个字符串参数。
    variables_map 
类在运行时存储命令行选项及其参数。
    Boost 
 parse_command_line 函数解析 argc  argv 参数。store  notify 方法帮助存储 vmap对象中的数据。
    vmap.count()
用于检测输入的是哪个命令行参数,并采取适当的动作

2. 提供多个参数和缩写的命令选项

命令行处理通常同时需要同一个命令选项的短名称和长名称。此外,您通常必须多次使用某个选项,以便收集该选项的所有参数。例如,您可能希望使用 -h  --help 来打印可用的命令:

#include  

#include  

#include  

using namespace std; 

 

int main (int ac, char* av[]) 

  boost::program_options::options_description options("command line options"); 

  options.add_options() ("help,h", "Use -h or --help to list all arguments") 

                    ("file", boost::program_options::value >( ), 

                         "Provide input file name"); 

  boost::program_options::variables_map vmap; 

  boost::program_options::store( 

      boost::program_options::parse_command_line(ac, av, options), vmap); 

  boost::program_options::notify(vmap); 

 

  if (vmap.count("help")) { 

      cout << options << endl; 

  } 

 

  if (vmap.count("file")) { 

      vector ifiles(vmap["file"].as< vector > ()); 

      vector::iterator vI; 

      cout << "Number of input files: " << ifiles.size() << endl; 

      cout << "Input file list: " << endl; 

      for(vI = ifiles.begin(); vI != ifiles.end(); ++vI) 

          cout << "\t" << *vI << endl; 

  } else { 

      cout << "No file specified\n"; 

  } 

 

  return 0; 

在使用 add_options 来添加命令选项时,较长和较短的选项之间使用逗号进行分隔。请注意,较长的选项(help) 必须在较短的选项 (h) 之前,代码才能正常工作。与使用单个字符串不同,file 选项现在是使用一个字符串向量来定义的。如果指定了 --file 选项多次,则会将所有收集到的file命令选项参数存储在关联的vector中。下面是使用不同的参数来多次指定 --h  --file 所获得的输出:

 ./a.out -h
command line options:
  -h [ --help ]         Use -h or --help to list all arguments
  --file arg            Provide input file name

No file specified

./a.out --file abc --file pqr
Number of input files: 2
Input file list:
        abc
        pqr

3. 解析位置选项

下面的程序,第一个参数转换为 --file=,第二个参数转换为 --do-file=

#include  

#include  

#include  

using namespace std; 

 

int main (int ac, char* av[]) 

  boost::program_options::options_description options("command line options"); 

  options.add_options() ("help,h", "Use -h or --help to list all arguments") 

                        ("file", boost::program_options::value(), 

                         "Provide input file name") 

                        ("do-file", boost::program_options::value(), 

                         "Specify commands file"); 

 

  boost::program_options::variables_map vmap; 

  boost::program_options::positional_options_description poptd; 

  poptd.add("file", 1); 

  poptd.add("do-file", 2); 

 

  boost::program_options::store( 

      boost::program_options::command_line_parser(ac, av). 

      options(options).positional(poptd).run(), vmap); 

  boost::program_options::notify(vmap); 

 

  if (vmap.count("file")) { 

     cout << "file: " << vmap["file"].as ( ) << endl; 

  } 

 

  if (vmap.count("do-file")) { 

     cout << "do-file: " << vmap["do-file"].as ( ) << endl; 

  } 

 

  return 0; 

下面是输出内容:

./a.out file1 dofile1
file: file1
do-file: dofile1

程序引入了新的类 positional_options_description。该类的 add 方法(add("command option", N))将位置 N 处的输入参数与命令行选项 "command option" 相关联。因此,./a.out file1 在内部解析为./a.out  --file=file1。另一个区别在于调用 program_options::store 方法的方式。与使用parse_command_line 例程不同,Boost 库要求您将 command_line_parser 例程与 store 方法结合在一起使用。

请注意,仍然可以使用 --file  --do-file 选项来调用该程序。最后,若要将所有的输入参数与同一个命令行选项相关联,您需要使用值-1 将该命令行选项添加到 positional_options_description 对象。下面是代码:


boost::program_options::positional_options_description poptd;
poptd.add("file", -1);
...

 

 

String test;

boost::program_options::value(&test)

这样可以将值赋值给test

 

 

54.         Gdb 条件断点

使用gdb 调试时,如果想在某个条件触发时停下,那么可以这么做:

gdb test.cpp:7 if a == 1

这个就是当a 等于1时停下

但是在test.cpp中没有a这个变量,比如我们想在某个条件停下,但是其中的值非常复杂,那么我们就在代码内部自己先做一层逻辑,然后做一个临时变量a,然后再打断点时触发,即可

 

55.         设置全局变量

在main方法的文件中定义一个全局变量如:

Int temp;

 

然后在需要使用该全局变量的文件中,声明:

extern int temp;

即可,注意只能放在外层,不能放在类内,否则会报如下错误:

/export/dev/hiphop-php/src/compiler/expression/scalar_expression.h:85: error: storage class specified for 'temp_gdb_hzg

 

56.         Vector 的reserve

vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!
原因如下:
      reserve是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用push_back()/insert()函数。

      resize是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的。

      两个函数的参数形式也有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小, 第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。

 

57.         BOOST_FOREACH用法

参照网址:

http://blog.csdn.net/jiangfriend/article/details/1713619

 

例子:

#include
#include

using namespace std;
#include
int main(int argc, char* argv[])
    {
    string str("The quick brown fox jumps over the lazy dog.");
    BOOST_FOREACH(char c,str)
        {
        cout<         }
    return 0;
    }

 

这里的BOOST_FOREACH 就是foreach迭代器,前面的是一个obj对象,后面的是一个该对象类型的集合

 

 

58.         a storage class can only be specified for objects and functions

/export/dev/hiphop-php/src/compiler/test_gdb_hzg.h:6: error: a storage class can only be specified for objects and functions

 

Static class Test_Gdb_Hzg{

         ….

};

 

由于在static 中没有添加变量名字;

 

Static class Test_Gdb_Hzg{

         ….

}test;

这样声明上名字即可

 

 

59.         当头文件引用冲突时加入if def

 

在.h 文件中加入:

 #ifndef __TEST_GDB_HZG_H__

 #define __TEST_GDB_HZG_H__

………

#endif

 

然后再多文件中引用就没有问题了

 

如果不这个,但文件引用会报如下错误:

has not been declared

当前文件中没有引入该头文件

 

如果引用了,会报重复声明了

 

所以在需要多文件引用时加入if def即可

 

60.         Vector back pop_back push_back

back 是获取尾元素;

pop_back是删除尾元素;

push_back是在尾部添加元素

 

61.         报未引用警告处理办法

当报了如下问题后:

/export/dev/hiphop-php/src/compiler/analysis/file_scope.cpp:413: warning: unused variable 'temp'

是由于声明了temp,但是后面未进行过调用,所以会报这个警告,这个不影响程序;

一般来说如:

Int temp=0;

Printf(“%d”,temp);

只要进行过调用就不会有问题了

 

62.         Gdb 读取vector数据

(gdb) p m_scopes

$89 =

  {

    {{

      px = 0x7fffe0277120,

      pn = {

        pi_ = 0x7fffe0277700

      }

    }      {

      px = 0x7fffe027d290,

      pn = {

        pi_ = 0x7fffe027dad0

      }

    }    }

}

如上面这样的就无法用:

p  m_scopes[0].px读取了;上面是有2个数据

那么这样去读取:

p  m_scopes.back()[0].px

 

 

63.         ~a取反的意思

如 a 二进制为:110110

那么~a则为:001001

64.         C++ map操作

map中元素的查找:

   find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。        

   map::iterator l_it;; 
   
l_it=maplive.find(112);
   if(l_it==maplive.end())
                cout<<"we do not find 112"<    else cout<<"wo find 112"<

如果I_it!=maplive.end()时则是查找成功

 

其他map 操作详见:

http://blog.csdn.net/allovexuwenqiang/article/details/5686583

 

 

65.         gdb 读取first 和second这样的vector 这样的值

p val

$37 = {

  first = {

    const, int>, false>> = {

      _M_cur_node = 0x5f228e0,

      _M_cur_bucket = 0x7fffc829f4e0

    }, },

  second = true

}

然后可以通过打印first

(gdb) p val.first

$38 = {

  const, int>, false>> = {

    _M_cur_node = 0x5f228e0,

    _M_cur_bucket = 0x7fffc829f4e0

  }, }

打印first的值

(gdb) p *val.first

$39 = (std::pair const, int> &) @0x5f228e0: {

  first = {

    px = 0x7fffc8276bc0

  },

  second = 2097152

}

就是在前面加星,如果想打里面的*val.first中的first,那么可以这样去打:

(gdb) p (*val.first).first

$41 = {

  px = 0x7fffc8276bc0

}

(gdb) p (*val.first).first.px

$42 = (HPHP::ClassScope *) 0x7fffc8276bc0

(gdb)

就是在值外面(*val.first)加上括号即可,然后调用first

也可以通过val.second调用value

 

 

66.         Std find查找

string variableName="$a->";

    if(variableName.find("->") != std::string::npos){

        cout<<"++"<

}

查找到后会输出++

 

67.         Stl map erase使用

Erase是删除map 中的某个对象

map testMap;

testMap. Erase(name)

 

68.         函数指针用法

#include "stdio.h"

//函数指针类型定义 void 返回值类型 fun_ptr 类型名称; int是参数

typedef void (*fun_ptr)(int);

void test(int a){

    printf("%d==========\n",a);

}

 

int main(){

    test(1);

printf("%p\n",&test);

         //把test的地址给t

fun_ptr t=test;

//执行t

    t(2);

    return 1;

}

t 和 test的地址一样

 

69.         linux 查看动态链接库的信息

ldd <可执行文件名>       查看可执行文件链接了哪些  系统动态链接库

nm <可执行文件名>       查看可执行文件里面有哪些符号

strip <可执行文件名>      去除符号表可以给可执行文件瘦身

如果我们想从可执行程序里面提取出来一点什么文本信息的话,还可以用strings命令

strings <可执行文件名>

 

 

70.         执行时报找不到动态链接库解决

执行编译语句:

gcc  --std=c99 -I/export/servers/mongodb_c/include/ -L/export/servers/mongodb_c/lib -o test_mongo_c test_mongo_c.c –lmongoc

编译成功后执行

./test_mongo_c时报了如下错误:

./test_mongo_c: error while loading shared libraries: libmongoc.so.0.7: cannot open shared object file: No such file or directory

通过ldd test_mongo_c 查看动态链接库,发现

linux-vdso.so.1 =>  (0x00007fff7c3c7000)

        libmongoc.so.0.7 => not found

        libc.so.6 => /lib64/libc.so.6 (0x00007f4afc602000)

        /lib64/ld-linux-x86-64.so.2 (0x00007f4afcbbf000)

找不到  libmongoc.so.0.7这个库,那么我们用root用户登录,然后打开

/etc/ld.so.conf

这个文件,在/etc/ld.so.conf文件中,加入我们xx.so的目录即可,如:

/usr/local/lib

/export/servers/mongo/lib

然后保存后执行,/sbin/ldconfig –v这样就生效了,然后重新编译文件,再执行就可以了,并且执行ldd查看动态链接库也有内容了

 

 

71.  指针调用异常解决

printf("%d---\n",cursor.limit);

编译时报如下错误:

test_connect.c:39:26: error: request for member 'limit' in something not a structure or union

cursor是个指针不是结构体

所以应改为:

printf("%d---\n",cursor->limit);

这样调用即可

 

72.  error:   crosses initialization of 'time_t t'解决方法

当报如下错误时:

error:   crosses initialization of 'time_t t'

 

原代码:

case BSON_DATE:

  bson_printf( "%ld" , ( long int )bson_iterator_date( &i ) );

   struct tm *lt;

time_t time_value=bson_iterator_time_t (&i);

   ………………….

   break;

 

将case用花括号括起来即可编译通过

case BSON_DATE:

 {

  bson_printf( "%ld" , ( long int )bson_iterator_date( &i ) );

   struct tm *lt;

time_t time_value=bson_iterator_time_t (&i);

   ………………….

   break;

 }

 

参照:

http://blog.sina.com.cn/s/blog_7a18bae10100s0lp.html

 

 

73.  socket 编程非阻塞

#include   

#include   

#include   

#include   

#include   

#include     

#include   

#include   

#include   

#include   

 

int   main(int   argc,   char   *argv[])

{

         int   fd,   retval;

         struct   sockaddr_in   addr;

         struct   timeval   timeo =   {3,0};

         socklen_t   len   =   sizeof(timeo);

         fd_set   set;

 

         fd   =   socket(AF_INET,   SOCK_STREAM,   0);

         if   (argc   ==   4)   timeo.tv_sec   =   atoi(argv[3]);

         /*

                   F_SETFL 设置文件描述词状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响

                   设置非阻塞O_NONBLOCK  (阻塞为~O_NONBLOCK)

         */

         int   savefl   =   fcntl(fd,F_GETFL);

         fcntl(fd,   F_SETFL,   savefl   |   O_NONBLOCK);

         addr.sin_family   =   AF_INET;

         addr.sin_addr.s_addr   =   inet_addr(argv[1]);

         addr.sin_port   =   htons(atoi(argv[2]));

         printf( "%d\n ",   time(NULL));

         if   (connect(fd,   (struct   sockaddr*)&addr,   sizeof(addr))   ==   0)

         {

                   close(fd);

                   printf( "connected..1\n ");

                   return   0;

}

 

/*

                   当连接状态为-1(connect),但是errno是EINPROGRESS

                   表示此时tcp三次握手仍旧进行,如果errno不是EINPROGRESS,则说明连接错误,程序结束。

         */

         if   (errno   !=   EINPROGRESS)

         {

                   close(fd);

                   perror( "connect..2 ");

                   return   -1;

         }

          /*将set清零使集合中不含任何fd*/

         FD_ZERO(&set);

         /*将fd加入set集合*/

         FD_SET(fd,   &set);

         /*

                   args0:最大的fd数量 最大值加1,不能错

                   非阻塞机制

                   args1:读fd 的set

                   args2:写fd的set

                   args3:fds错误的set

                   args4 时间

                   retval:

                   负值:select错误 正值:某些文件可读写或出错 0:等待超时,没有可读写或错误的文件

         */

         retval = select(fd + 1,   NULL,   &set,   NULL,   &timeo);

         if   (retval   ==   -1)

         {

                   close(fd);

                   perror( "select ");

                   return   -1;

         }

         else   if(retval   ==   0)

         {

                   close(fd);

                  fprintf(stderr,   "timeout\n ");

                   printf( "%d\n ",   time(NULL));

                   return   0;

         }

         /*测试fd是否在set集合中*/

         if(FD_ISSET   (fd,&set))

         {

                   int   error   =   0; 

                   socklen_t   len   =   sizeof   (error);

                   if(getsockopt(fd,   SOL_SOCKET,   SO_ERROR,   &error,   &len)   <  0)

{

printf   ( "getsockopt  fail,connected  fail\n ");

return   -1;

                   }

                  

                   if   (error   ==   ETIMEDOUT)

                   {

                            printf   ( "connected   timeout\n ");

                   }

        

                   if(error   ==   ECONNREFUSED)

                   {

                            printf( "No   one   listening   on   the   remote  address.\n ");

                            return   -1;

                   }

         }

         printf   ( "connected   ..   3\n ");

         fcntl(fd,   F_SETFL,   savefl);

         close   (fd);

        

         return   0;

}

 

上面是一个连接超时验证的一个socket连接代码;

非阻塞连接参照:

http://hi.baidu.com/johntech/item/75ef7aea922cd23286d9dee1

 

注意:

(1)errno的值为111 (ECONNREFUSED ),正确我应该需要的是115(EINPROGRESS )

正确写法:errno 为EINPROGRESS 

fd   =   socket(AF_INET,   SOCK_STREAM,   0);

int   savefl   =   fcntl(fd,F_GETFL);

fcntl(fd,   F_SETFL,   savefl   |   O_NONBLOCK);

错误:errno为ECONNREFUSED (111)

int   savefl   =   fcntl(fd,F_GETFL);

fcntl(fd,   F_SETFL,   savefl   |   O_NONBLOCK);

fd   =   socket(AF_INET,   SOCK_STREAM,   0);

 

记住错误红色部分需要在socket下面才对,先连接socket让,后在设置阻塞状态

Errno状态参照:

http://baike.baidu.com/view/3485007.htm

 

Socket函数:

头文件:

#include

#include

函数原型 int socket(int domain, int type, int protocol);

例子:

fd   =   socket(AF_INET,   SOCK_STREAM,   0);

第一个参数指定应用程序使用的通信协议的协议族,对于TCP/IP协议族,该参数置AF_INET;

第二个参数指定要创建的套接字类型,流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM、原始套接字SOCK_RAW(WinSock接口并不适用某种特定的协议去封装它,而是由程序自行处理数据包以及协议首部);

第三个参数指定应用程序所使用的通信协议。此参数可以指定单个协议系列中的不同传输协议。在Internet通讯域中,此参数一般取值为0,系统会根据套接字的类型决定应使用的传输层协议。

第三个参数protocol:

一般设置为0(IPPROTO_IP 0),6(IPPROTO_TCP)

参照:

http://baike.baidu.com/view/9796742.htm

 

 

connect函数:

表头文件

#include

#include

定义函数

int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);

函数说明

connect()用来将参数sockfd 的socket 连至参数serv_addr 指定的网络地址。结构sockaddr请参考bind()。参数addrlen为sockaddr的结构长度。

参数

参数一:套接字描述符

参数二:指向数据机构sockaddr的指针,其中包括目的端口和IP地址

参数三:参数二sockaddr的长度,可以通过sizeof(struct sockaddr)获得

返回值

成功则返回0,失败返回-1,错误码GetLastError()。

参照:

http://baike.baidu.com/view/888434.htm

getaddrinfo函数

参照:

http://baike.baidu.com/view/6757218.htm

 

 

74.         c 指针

void test(int *a){

         //a是a的地址,*a 是指向a的值

}

 

 

75.         error: no matching function for call to错误解决

报如下问题:

/export/dev_hhvm/hiphop-php_hzg/src/runtime/ext/ext_ice.cpp:39:55: error: no matching function for call to 'Ice::Communicator::stringToProxy(const HPHP::String&)'

 

是由于方法的参数不匹配造成的,如Ice::Communicator::stringToProxy(const HPHP::String&)

传入的类型是const HPHP::String& ,但是实际的类型是std::string,所以就会报这个问题了

 

 

76.         multiple definition of `HPHP::classInfoMap'

当编译时报了如下错误:

multiple definition of `HPHP::classInfoMap'

 

在头文件中定义了一个classInfoMap全局变量

Classinfo.h

std::map classInfoMap;

 

这样定义全局变量时,需要在头文件在定义的变量前加上extern

extern Std::map classInfoMap;

 

然后在cpp上进行一次声明即可:

std::map classInfoMap;

 

 

 

77.         undefined reference to `HPHP::Ice_ClassInfo::Ice_ClassInfo()

当编译时报了如下错误:

/export/dev_hhvm/hiphop-php_hzg/src/runtime/ext/ext_ice.cpp:349: undefined reference to `HPHP::Ice_ClassInfo::Ice_ClassInfo()'

 

找到349行,发现时一个实例化语句如:

Ice_ClassInfo* ci = new Ice_ClassInfo();

但是Ice_ClassInfo这个类已经在头文件声明了

在头文件中找到了Ice_ClassInfo类:

Ice_ClassInfo();

发现只对Ice_ClassInfo类进行了构造函数的声明,并没有实现,所以报了没有引用的问题,

那么我们在cpp中进行实现的定义或者在头文件中

Ice_ClassInfo(){};这样实现即可

 

 

78.         undefined reference to `vtable for SequenInfo‘

当编译时,报了如下错误:

undefined reference to `vtable for SequenInfo‘

 

提示虚函数表没有SequenInfo声明这个类,

这是由于我的SequenInfo中有一个虚函数在基类中没有声明,所以删除掉SequenInfo类中的在基类中没有用到的虚函数即可编译通过,而且需要注意的是,使用多态时,子类和基类都需要实现构造和虚构函数,并且实现虚函数,否则都会出现如上错误;

例:

Class Base{

public:

         Base(){};

       ~Base(){};

         virtual bool usesClasses(){};

};

 

Class SubClass{

         public:

                   SubClass(){};

                   ~ SubClass(){};

                   virtual bool usesClasses(){};

                   /*

                            这个虚函数在实例化SubClass时就会报如上错误,因为在Base类中没有定义这个虚函数,所以删除它即可,而且上面的构造函数,虚构函数都需要对应实现

                   */

                   virtual bool getId(){};

}

 

 

79.         List 用法

#include

#include

using namespace std;

 

class A{

        public:

                int v;

                list next;

};

int main(){

        list test_list;

        for(int i=0;i<4;i++){

                A *a=new A();

                a->v=i;

                list list;

                A *b=new A();

                b->v=i+2;

                                     //插入内容

                list.push_back(*b);

                a->next=list;

                test_list.push_back(*a);

        }

        list::iterator itr;

                   //遍历

        for(itr=test_list.begin();itr!=test_list.end();itr++){

                cout<v<

                list::iterator itr_n;

                for(itr_n=itr->next.begin();itr_n!=itr->next.end();itr_n++){

                        cout<<"==================="<

                        cout<v<

                }

 

        }

        return 0;

}

 

 

80.         syscall exception: Resource temporarily unavailable

pthread_create 报了如下错误:

 

syscall exception: Resource temporarily unavailable

 

有几种暂时解决方式:

(1)       ulimit –u 65535 这样是设置是改子进程数量

(2)       ulimit –a查看

然后修改 ulmit –s 1024 是修改stack size也就是线程栈的大小

 

还有代码解决方式

 

 

81.      Gdb 根据地址和类型取值

p {VolumePath} 0x6141d60

 

p {类型} 地址

 

 

82.         source type is not polymorphic

当c++ 使用

P_ClassInfo *p_classInfo=dynamic_cast(ismc->typeInfo);

转换是报了如下错误:

source type is not polymorphic

源类型不是多态,那么是由于在类中没有定义虚函数

 

 

83.         crosses initialization

当编译器报如下错误时:

error:   crosses initialization of 'HPHP::P_PrimitiveInfo* p_primitiveInfo'

是 由于 switch的case后面没有加大括号,因为

如果大括号,则会出现crosses initialization错误,因为编译器会认为局部变量i可能会被绕过申明而被直接进入其作用域。

见:

http://blog.sina.com.cn/s/blog_489239370100asc4.html

 

 

84.         test.cpp:16:47: error: 'malloc' was not declared in this scope

c++ 编译报了这个错误,添加个头文件就可以; 

#include

 

 

85.         安装libevent报错解决

当执行make 时,libevent报了如下错误,由于libtool版本产生的

Version mismatch error.  This is libtool 2.4, but the libtool: definition of this LT_INIT comes from libtool 2.2.6b

解决方法下载libtool2.2.6b,然后安装,需要默认安装,配置环境变量不知道为何无作用

安装完毕后解决该问题

 

86.         Const char* 强转为 char *

const char * str = "asd";

char* p =const_cast(str.c_str());

 

87.         int 转换成枚举类型

如枚举类型为:

Enum Kind{

         Kind_a,

         Kind_b,

         Kind_c

} kind;

 

Int a=1;

kind=Kind(a);

红色部分是强转方法;

 

 

你可能感兴趣的:(c 和c ++总结)