2016年9月11日

CMake使用

cmake学习(一)静态库与动态库构建

(.so)共享库,shared object:节省空间,在运行时去连接,如果执行机器上没有这些库文件就不能执行。
(.a)静态库,archive:静态库和程序化为一体,不会分开。
通过 ldd命令可以查看一个可执行程序所依赖的的共享库。
使用环境变量LD_LIBRARY_DIRECTORY可以指定共享库位置


一、编译共享库:
ADD_LIBRARY(hello SHARED ${SHARED_LIBRARY})

二、添加静态库:
ADD_LIBRARY(hello STATIC ${STATIC_LIBRARY})
因为默认规则是不能有相同名字的共享库与静态库,所以当生成静态库的时候(so后缀),共享库会被删除,因为只能允许一个名字存在,相同名字的会被替代(hello),所以需要通过SET_TARGET_PROPERTIES()来解决这个问题,例子:
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
cmake在构建一个target的时候,会删除之前生成的target,一样是通过设置SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)来达到目的
三、动态库的版本号:
同样是通过SET_TARGET_PROPERTIES()来设置
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION:动态库版本
SOVERSION:API版本
最后生成的结果是:
libhello.so.1.2
libhello.so.1->libhello.so.1.2
libhello.so->libhello.so.1
四、安装:
INSTALL(TARGETS hello hello_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
INSTALL(TARGETS hello.h
DESTINATION include/hello)
其他常用的属性 PERMISSIONS:设置权限;RATTERN:设置正则表达式


Summary:
ADD_LIBRARY():添加一个库,共享库,静态库,模块
SET_TARGET_PROPERTIES():设置输出名称,版本号,解决相同target被删除的问题
GET_TARGET_PROEERTIES():与SET功能相对

cmake学习(二)常用变量和常用环境变量
一、变量的引用方式是使用“${}”,在IF中,不需要使用这种方式,直接使用变量名即可
二、自定义变量使用SET(OBJ_NAME xxxx),使用时${OBJ_NAME}
三、cmake的常用变量:
CMAKE_BINARY_DIR,PROJECT_BINARY_DIR,_BINARY_DIR:
这三个变量内容一致,如果是内部编译,就指的是工程的顶级目录,如果是外部编译,指的就是工程编译发生的目录。
CMAKE_SOURCE_DIR,PROJECT_SOURCE_DIR,_SOURCE_DIR:
这三个变量内容一致,都指的是工程的顶级目录。
CMAKE_CURRENT_BINARY_DIR:外部编译时,指的是target目录,内部编译时,指的是顶级目录
CMAKE_CURRENT_SOURCE_DIR:CMakeList.txt所在的目录
CMAKE_CURRENT_LIST_DIR:CMakeList.txt的完整路径
CMAKE_CURRENT_LIST_LINE:当前所在的行
CMAKE_MODULE_PATH:如果工程复杂,可能需要编写一些cmake模块,这里通过SET指定这个变量
LIBRARY_OUTPUT_DIR,BINARY_OUTPUT_DIR:库和可执行的最终存放目录
PROJECT_NAME:你猜~~

 

四、cmake中调用环境变量
1.Using $ENV{NAME} : invoke system environment varible.
We can use "SET(ENV{NAME} value)" as well. note that the "ENV" without "$".
2.CMAKE_INCLUDE_CURRENT_DIR equal to INCLUDE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})


五、其他的内置变量
1.BUILD_SHARED_LIBS:set the default value when using ADD_LIBRARY()
2.CMAKE_C_FLAGS: set compiler for c language
2.CMAKE_CXX_FLAGS: set compiler for c++ language


六、区分debug和release
在工程目录下,cmake -DCMAKE__BUILD_TYPE=DEBUG(RELEASE),再执行make


七、指定编译32bit或64bit程序
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")

cmake学习(三)常用指令

一、基本指令:
INCLUDE_DIRECTORIES(${includedir}) #-I。
LINK_DIRECTORIES(${libdir}) #-L
TARGET_LINK_LIBRARIES(helloworld ${linkflags}) #-l
ADD_DEFINITIONS(${cflags}) #-D
 
1、ADD_DEFINATIONS:向C/CPP添加宏定义,相当于gcc中的-D,参数之间用空格分割
2、ADD_DEPENDICIES(target_name, depend_name):定义target对其他target的依赖关系
3、AUX_SOURCE_DIRECTORY(dir VARIBLE):把目录下的所有源文件保存在变量中,基本用来创建源文件列表
4、ADD_EXECUTABLE:指定目录,生成执行文件
5、EXEC_PROGRAM:外部调用指令,可移执行任何外部命令,后面加参数,例子如下:
EXEC_PROGERAM(ls ARGS"*.c" OUTPUT_VARIBLE LS_OUTPUT RETURN_VALUE LS_RVALUE)
IF(not LS_RVALUE)
MESSAGE(STATUS "xxx")
ENDIF(not LS_RVAULE)
PS.这里执行ls *.c指令,执行成功的话,返回0。
6、FILE指令:
FILE(WRITE file_name "content")
FILE(APPEND file_name "content")
FILE(READ file_name varible)
FILE(WRITE file_name "content")
7、FIND_系列指令:
LIBRARY( name path):
FIND_LIBRARY(Xorg X11 /usr/lib64)
IF(not Xorg)
MESSAGE(STATUS "no Xorg")
ENDIF(not Xorg)
FILE( name path)
PATH( name path)
PROGRAM( name path)
PACKAGE( [major.minor][QUIET][NO MODULE][[REQUIRED][COMPONTS][componts....]])
最后一条,用来调用放在CMAKE_MODULE_PATH下的Find.cmake模块,也可以自定义Find模块
首先通过SET(CMAKE_MODULE_PATH /home/...)来指定位置

8、控制指令:
IF(expression),ELSE(expression),ENDIF(expression)
express举例:
否定:空,0,N,NO,OFF,FALSE,NOTFOUND或_NOTFOUND
肯定:COMMAND cmd,EXISTS dir/file,variable MARCHES regex等等等等还有很多~~~随用随查吧


cmake学习(四)模块的使用和自定义模块

FIND_PACKAGE
每一个模块都会产生如下变量
_FOUND
_INCLUDE_DIR
_LIBRARY or _LIBRARIES
如果_FOUND为真,把_INCLUDE_DIR加入到INCLUDE_DIRECTORIES中,_LIBRARY加入到TARGET_LINK_LIBRARIES中。

编写属于自己的FindHello模块:
1.FIND_PATH(HELLO_INCLUDE_DIR hello.h /usr/include/hello /usr/local/include/hello)
2.FIND_LIBRARY(HELLO_LIBRARY_DIR NAMES hello PATH /usr/lib /usr/local/lib)
  IF(HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
  SET(HELLO_FOUND TRUE)
  ENDIF(HELLO_INCLUDE_DIR)
3.FIND_PACKAGE([major.minor][QUIET][NO_MODULE]
[[REQUIRED|COMPONENTS][componets...]])
QUIET参数:去掉输出信息
REQUIRED参数:共享库是否是工程必须的,如果是必须的,那么找不到
如果在src中想调用hello模块中的内容
FIND_PACKAGE(HELLO)
为了可以让工程找到FindHELLO.cmake
在主工程的CMakeList.txt中,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_PATH}/cmake)
通过设置FIND_PACKAGE(HELLO QUIET)可以去掉输出信息

Cmake CMAKE_BUILD_TYPE specification

That’s because no build type has been specified to CMake. The build type is a feature most IDE have, it allows you to compile your program in “debug” mode, for easily single-stepping through it with a debugger, or in “release” mode, with speed optimization enabled.

To fix this you simply need to specify a build type in the CMakeLists.txt file, in this way:


if( NOT CMAKE_BUILD_TYPE )
  set( CMAKE_BUILD_TYPE Debug CACHE STRING
       "Choose the type of build, options are: None Debug Release RelWithDebInfo
MinSizeRel."
       FORCE )
endif()

when cmake is run without specifying the build type using -D CMAKE_BUILD_TYPE, it is the Debug mode that is selected as the default.


 

posted @ 2016-09-11 22:52 Daywei 阅读(1218) | 评论 (0)编辑 收藏

2016年6月28日

SDL认识

     SDL是一个轻量级的,用C语言开发的多媒体库。它包含了图像绘制、文字绘制、事件处理、声音播放等模块。因为SDL的易用以及它的扩展库的完整性,很多2D游戏都使用SDL开发,其中就包括这几年大热的移动平台上的游戏《愤怒的小鸟》。

然后说说从个人角度上看SDL的特点。

1.跨平台。确确实实是跨了N个平台,甚至包括NDS这种平台。有了SDL,你甚至可以在windows、linux、Android上任意移植你的游戏。当然,前提是你目标平台的编译器认识你的代码( ̄▽ ̄)”。有了SDL泥甚至可以只用c语言开发安卓游戏哟。

2.开源。

3.SDL2.0绘图效率很高。事实上相较之SDL1.2我个人比较喜欢SDL2.0的原因也是在此。个人感觉(其实我没看过源码)SDL1.2应该是个跟当年的DirectDraw差不多的东西,像素填充什么的,有相当程度上是要磨CPU的。而SDL2.0从绘图方式上就革新了,抛弃了之前的surface与clip的模式,把实际绘制的东西改为了Texture,而把之前的surface改为了创建Texture的一个临时环节。而texure,顾名思义,其实就是DirectX、OpenGL这些底层的3D硬件加速API的贴图。

当下DirectX、OpenGL标准下的显卡的渲染管线无非就是:1.把顶点(可以理解成坐标)传给显卡 。2.把texture传给显卡。 3.告诉显卡怎么处理这些数据(shader)。 4.显卡把东西给你显示出来。而基于DirectX、OpenGL(移动平台是OpenGL ES)的SDL2.0,正是恰好地利用了当下显卡的能力。

4.SDL可以用作3D图像引擎和底层DirectX/OpenGL API的中间层。当然,其实如果把SDL这样用的话,那就真是很薄的一层了:)

5.易用。这是相对而言的,比如在windows上,你用了SDL这个库之后,基本就不用去理会Windows那些又臭又长用不着的参数又多的API了。我不是在讨论信仰问题也不是要诋毁windows,我是在客观陈述windows api那个要初始化一个窗口必须要堆100行代码的设定实在是打击初学者积极性的事实。

SDL_image、SDL_ttf、SDL_mixer、SDL_net 外部扩展库,也是不错的选择。

性能没有测试,仅从写代码角度上来说,个人感觉2.0将操作给弄得复杂了。

1.2---------------------------------------
只有SDL_Surface的概念,屏幕是surface,图片,文字等都是surface,
只要将准备好的各种图片,贴到屏幕里去(SDL_BlitSurface);再刷一下屏幕(SDL_Flip全局的、或SDL_UpdateRect局部的)就ok了。。。

SDL_Init(SDL_INIT_EVERYTHING);

SDL_Surface* screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
SDL_Surface* bmp = SDL_LoadBMP("back.bmp");
SDL_BlitSurface(bmp, 0, screen, 0);
SDL_Flip(screen);

while(SDL_WaitEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
return;
}
}
SDL_Quit();
2.0---------------------------------------
整出了SDL_Window,SDL_Renderer,SDL_Texture新的3个东西。
并且我要画一张图,先要得到surface,然后转换为texture,再临时贴到renderer,最后才刷屏。

SDL_Init(SDL_INIT_EVERYTHING);

SDL_Window* window = SDL_CreateWindow("hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_Surface* surface = SDL_LoadBMP("back.bmp");
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, 0, 0);
SDL_RenderPresent(renderer);

while(SDL_WaitEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
return;
}
}
SDL_Quit();

其实,我真心不觉得提出SDL_Window,SDL_Renderer,SDL_Texture这些概念先进性在哪里?可能是与openGL的概念保持一致吧。
而且从维护的角度出发,不管sdl2.0性能提升了多少,如果接口本身不需要改动,不是更加好么?

---------------------------------------------
最后我发现,同样是渲染的窗口
1.2用SDL_Flip(screen);之后被其他窗口挡住之后,回来画面还是在的;
2.0用SDL_RenderPresent(renderer);之后被其他窗口挡住之后,回来画面就不在了;

posted @ 2016-06-28 00:17 Daywei 阅读(575) | 评论 (0)编辑 收藏

2015年12月6日

OpenCV 使用问题记录

     摘要:     OpenCV从1.0到现在的3.0,变化还是相当大的。大趋势是从C结构层次到C++类层次的转变。先从OpenCV底层的图像数据结构谈起,1.0时 图像数据结构是IplImage,之后是cvmat,之后2.2中出现了CvvImage,之后就是cv::mat,2.3之后CvvImage就被废弃了。 opencv中对图像的处理是最基本的操作,一般的图像类型为Ipl...  阅读全文

posted @ 2015-12-06 12:20 Daywei 阅读(1905) | 评论 (0)编辑 收藏

2015年3月17日

SQL使用记录

     摘要: 问题:Update字段来自子查询或者来自其他表字段 Update 语句 Update 语句用于修改表中的数据。 语法:UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值SQL update select语句 最常用的update语法是: UPDATE <table_name> SET <column_name1> = <value&...  阅读全文

posted @ 2015-03-17 15:43 Daywei 阅读(734) | 评论 (0)编辑 收藏

2014年8月22日

Exceptional C++ 读书笔记2

永远不要用#include包含不必要的头文件

如果只需要流的前置声明,应该优先使用#include<iosfwd>

只需要前置声明时,绝不要用#include包含相应的头文件。

如果使用聚合关系就已经足够,就不要使用继承。

要避免使用内联或者复杂的调整方法,除非通过性能分析证明这确实是必要的。

正确使用名字空间。如果将一个类放入名字空间,那么同时要保证将这个类的所有辅助函数和运算符函数也放入相同的名字空间。否则,你将在代码中发现奇怪的结果。
要理解这五种不同类型的内存,了解他们为什么是不同的,以及他们各自的行为又是怎么样:栈(自动变量)、自由存储(new/delete)、堆(malloc/free)、全局(静态变量、全局变量、文件作用域变量等)、常量数据(字符串常量等)。

优先使用自由存储(new/delete),避免使用堆(malloc/free)。

对于“堆”和“自由存储”进行区分,这一点很重要,因为在C++标准中有意避开了这两种类型的内存是不是相关的这个问题。例如,当通过::operator delete()函数来释放内存时,在C++标准的18.4.1.1中,最后一项是这样的:
“ 在C++标准中并没有规定,在哪些情况下,在通过operator delete回收的存储空间中,有一部分或者全部的控件可以再随后调用operator new或者calloc,malloc以及realloc等函数时被重新分配,这些函数的声明时在<cstdlib>中。”
而且,在C++标准中也没有规定,new/delete是否需要通过malloc/free来实现。不过,在C++标准20.4.6节的第3段和第4段中规定了,malloc/free一定不能使用new/delete来实现:“calloc、malloc和realloc函数不会通过调用::operator new()来分配存储空间。函数free()不会通过调用::operator delete() 来释放内存。”

如果在类中定义了new和delete中的任意一个运算符函数,那么一定要同时定义另外一个。

通常应该显式地将函数operator new ()和operator delete()声明为静态函数。他们永远都不能使非静态成员函数。

永远都不要通过多态的方式处理数组。

优先选择使用vector或者deque,而不是数组。

在编写拷贝赋值运算符函数时,永远都不要指望能够通过对自我赋值进行检测来保证函数的正确性;应该在拷贝赋值运算符函数中使用“创建临时对象并进行交换”的惯用法,这种方法不仅是异常安全的,而且在处理自我赋值时也是安全的。

可以将自我赋值检测作为一种优化手段,以避免不必要的工作,这是正确地做法。

不仅要避免编写类型转换运算符函数,而且还要避免编写隐式的构造函数。

尽量编写异常安全的代码。在编写代码时应该始终遵循:即使在出现异常时,资源仍然能够被正确地释放,并且数据也总是处于一致的状态。

避免使用语言中那些不常用的特性,而应该使用最简单并且有效的技术。

拷贝初始化过程绝不是赋值过程,因此在初始化中永远都不会调用函数T::operator=()。是的,我知道在初始化语句中有一个“=”符合,但不要被它迷惑。它只是从C语言中沿用过来的一种语法,并不代表赋值运算。

如果可能的话,优先使用“T t(u);”这种形式,而不是“T t=u;”的形式。通常,能能够时候后者的地方,都可以使用前者,并且使用前者还有更多的好处——例如,可以带多个参数。

在函数声明中,如果参数是以传值方式来传递的,则不要使用const。而如果在这个函数的定义中,参数是不能被修改的,那么应该使用const。

对于不是内置类型的返回值来说,当使用返回值的方式而不是返回引用的方式时,应该优先选择返回const值。

const 和mutable都是你的朋友

优先使用新形式的类型转换。

不要通过类型转换去掉常量属性,而应该使用mutable。

避免使用向下的类型转换。

优先通过引用方式来传递对象参数,而不是传值方式,并且在所有可能的地方都使用const。

避免使用内联,除非从性能的分析上来看确实有必要这么做。

避免使用全局变量或者静态变量。如果必须使用,那么一定要特别注意这些变量的初始化顺序。

在构造函数的初始化列表中,应该把 基类按照他们在类定义中出现的先后顺序进行排列。

在编写代码时,永远都不应该依赖函数参数的求值顺序

posted @ 2014-08-22 15:00 Daywei 阅读(1509) | 评论 (0)编辑 收藏

Exceptional C++ 读书笔记1

绝对不要对无效的迭代器执行解引用(dereference)操作

用于不要将异常安全性放在事后考虑。异常安全性会影响到类的设计。它永远都不会“只是一个实现细节”。

在传递对象参数时,选择const&方式而不是传值方式。

对于程序运行中不会改变的值,应该预先计算并保存起来备用,而不是重复地创建对象,这是没有必要的。

通常,为了保持一致性,应该使用前置递增来实现后置递增,否则,当其他用户在使用你的类时,可能会得到奇怪结果。

优先选择使用前置递增。只有在需要初始值时,才使用后置递增。

在进行隐式类型转换时,要注意在转换过程中创建的 临时对象。要避免这个问题,一个好办法就是尽可能地通过显式的方式来构造对象,并避免编写类型转换运算符。

记住对象的生存期。永远,永远,永远都不要返回指向局部对象的指针或引用;它们没有任何用处,因为主调代码无法跟踪它们的有效性,但却可能会试图这么做。

尽可能地重用代码——尤其是标准库中的代码——而不是自己去编写代码,这样更快、更容易,也更安全。

如果在函数中不打算处理所抛出的异常,那么应该将异常转发给能够进行处理的上层调用者。

在编写代码时应该始终遵循:即使在出现异常时,资源仍然能够被正确地释放,并且数据也总是处于一致的状态。

遵循标准的异常安全规则:永远不要在析构函数、重载运算符函数operator delete()或者operator delete[]()中抛出异常; 在编写每个析构函数和内存释放函数时,要假设存在着“throw()”这样的异常规范。

遵循标准的异常安全性规则:在每个函数中,要将所有可能会抛出异常的代码单独放在一起,并且对这些代码进行安全处理。然后,当你确认这些代码执行的工作都已经成功地完成时,才可以使用不会抛出异常的操作来修改程序的状态。

永远都不要到最后才实现异常安全性。异常安全性会对类的设计产生影响。它永远都不会“只是一个实现细节”。

优先考虑实现内聚。要努力使每段代码——每个模块、每个类、每个函数——都只有单一的,并且是明确定义的功能。

“异常不安全”总是与“拙劣的设计”结伴的。如果程序的设计逻辑清晰,那么即使有一段代码不是异常安全的,一般来说也不会有太大问题,并且可以很简单地进行修正。但如果有一段代码由于设计问题而不能被编写成异常安全的,我们通常都会认为这个设计时拙劣的。下面是两个拙劣设计的示例。
示例1:如果在一个函数中需要实现两个不同的功能,那么这个函数很难被编写成异常安全的。
示例2:如果在拷贝赋值运算符函数中必须对自我赋值进行检测,那么这个函数也可能不是完全异常安全的

遵循标准的异常安全性规则:以“获得资源也就意味着初始化”这种模式来分离资源的所有权和资源的管理权。

在进行设计中,要始终牢记重用性。

优先采用“ a op=b;”这种写法,而不是"a = a op b;"(这里的op表示某个运算符)。这种写法更为清晰,效率也高。

如果定义了某个运算符(例如,operator+),那么通常还应该同时定义与这个运算符相对应的赋值运算符(例如,operator+=)。并且用后者来实现前者。而且,还应该维护op和op=之间的自然关系。

在C++标准中规定:运算符=,(),[]和->必须被定义为成员函数,而在类中定义的new,new [],delete和delete[]等运算符函数必须是静态成员函数。对于其他的运算符函数:
     如果运算符函数是用于流I/O的opeator>>或者operator<<,或者如果运算符函数需要对其左操作数进行类型转换,或者运算符函数可以通过类的公有接口来实现,那么将这个函数定义为非成员函数(在前两种情况中,如果需要的话也可以被定义为友元函数);如果运算符函数需要实现虚函数的行为,那么增加一个虚函数来提供虚函数的行为,并用这个虚成员函数来实现运算符函数否则将预算富函数定义为成员函数。

在函数opeator>>和operator<<中应该始终返回对流对象的引用。

将基类的析构函数定义为虚函数(除非你能保证,永远都不会有人通过指向基类的指针来删除派生类的对象)。

如果在派生类中定义的函数与基类中的函数有相同的名字,并且你不想隐藏基类中函数,那么应通过using声明语句将基类的这个函数引入到派生类的作用域中。

永远不要改变被覆盖的基类函数中的默认参数值。

除了对真正的Liskov IS-A和WORKS-LIKE-A关系进行建模之外,永远都不要使用共有继承。所有被覆盖的成员函数不能超过实际需求的范围,同时也不能小于这个范围。

使用公有继承的目的是重用代码(编写以多态的方式使用基类对象的代码),而重用(基类中的)代码并不一定要使用公有继承。

对“is implemented in terms of”这种关系建模时,应该优先选择成员关系/包含的方式,而不是私有继承的方式。只有非用继承不可时,才应该使用私有继承——也就是说,当需要访问保护成员或者需要覆盖虚函数时,才使用私有继承。永远都不要只是为了代码重用而使用共有继承。

对于广泛使用的类,应该优先使用编译器防火墙这种惯用法(也叫做Pimpl惯用法)来隐藏实现细节,通过一个不透明的指针(指向一个进行了前置声明但又没有定义的类)来保存私有成员(包括状态变量和成员函数),声明这个指针时可采用“struct XxxxImpl* pImpl;XxxxImpl* pimpl_;”这样的形式。例如:“class map{ private :struct MapImpl;MapImpl* pimpl_;}”

包含,也可以叫做“聚合”,“分层”,“HAS-A”或者“委托”。优先选择包含而不是继承,对于IS-IMPLEMENTED-IN-TERMS-OF这种关系建模时,应该优先考虑使用包含,而不是继承。

posted @ 2014-08-22 11:50 Daywei 阅读(1563) | 评论 (0)编辑 收藏

2014年7月24日

从缺陷中学习C/C++


有符号int与无符号int比较的后果
int i = -1;
unsigned 
int ud=1;
if(i < ud)
{
    printf(
"true");
}

else
{
    printf(
"false");
}
一看结果应该是打印出true,但事实却是false。
signed int 型变量被转换成unsigned int型变量。-1转换成unsigned int的结果是一个非常巨大的正整数(32位系统上是2的32次方-1),需要进行强转为int型。

位域变量
struct data
{
int flag:1;
int other:31;
}
;
printf(
"data size %d\n",sizeof(data));
data test1;
test.flag
= 1;
if(test.flag ==1)
{
printf(
"true");
}

else
{
printf(
"false");
}
int的位域变量,而用一个bit表示int时,这一位是用来表示有符号位的,带符号的一个bit的位域变量的取值范围是0或-1.无符号的一个bit的位域变量的取值范围是0或1,故1赋给flag时会出现溢出,flag变为-1.
Reference:http://wenku.baidu.com/view/670eff4bf7ec4afe04a1dfd7.html

posted @ 2014-07-24 15:29 Daywei 阅读(1349) | 评论 (0)编辑 收藏

2014年6月25日

Effective STL(5)——算法

1.确保目标空间足够大

2.了解各种与排序有关的选择
  如果需要对vector、string、deque或者数组中的元素执行一次完全排序,那么可以使用sort或者stable_sort。
  如果有一个vector、string、deque或者数组,并且只需要对等价性最前面的n个元素进行排序,那么可以使用partial_sort。
  如果有一个vector、string、deque或者数组,并且需要找到第n个位置上的元素,或者,需要找到等价性最前面的n个元素但又不必对这n个元素进行排序,那么,nth_element正是你所需要的函数。
  如果需要将一个标准序列容器中的元素按照是否满足某个特定的条件区分开来,那么,partition和stable_partition可能正是你所需要的。
  如果你的数据在一个list中,那么你仍然可以直接调用partition和stable_partition算法;可以用list::sort来替代sort和stable_sort算法。但是,如果你需要获得partial_sort或nth_element算法的效果,那么,正如前面我所提到的那样,你可以有一些简洁的途径来完成这项任务。

3。如果确实需要删除元素,则需要在remove这一类算法之后调用erase。

   remove不是真正意义上的删除,因为它做不到。

4.对包含指针的容器使用remove这一类算法时要特别小心。会导致资源泄露。

5.了解哪些算法要求使用排序的区间作为参数。

6.通过mismatch或lexicographical_compare实现简单地忽略大小写的字符串比较

7.理解copy_if算法的正确实现

8.使用accumlate或者for_each进行区间统计。

posted @ 2014-06-25 17:06 Daywei 阅读(1416) | 评论 (0)编辑 收藏

2014年6月13日

Effective STL(4)——迭代器

1.iterator 优先于const_iterator、reverse_iterator及const_reverse_iterator

2.使用distance和advace将容器的const_iterator转换成iterator

3.正确理解由reverse_iterator的base()成员函数所产生的iterator的用法。

4.对于逐个字符的输入请考虑使用istreambuf_iterator

posted @ 2014-06-13 15:00 Daywei 阅读(1256) | 评论 (0)编辑 收藏

2014年5月16日

Effective STL(3)——关联容器

1.理解相等(equality)和等价(equivalence)的区别

相等的概念是基于operator==的。等价关系是以“在已排序的区间中对象值得相对顺序”为基础的。如果从每个标准关联容器的排列顺序来考虑等价关系,那么着将是有意义的。标准关联容器室基于等价而不是相等的。标准关联容器总是保持排列顺序的,所以每个容器必须有一个比较函数(默认less)来决定保持怎样的顺序。等价是按照比较函数子。因此,标准关联容器的使用者要为所使用的每个容器指定一个比较函数(用来决定如何排序)。如果该关联容器使用相等来决定两个对象是否有相同的值,那么每个关联容器除了用于排序的比较函数外,还需要另一个比较函数来决定两个值是否相等(默认情况下,该比较函数应该是equal_to,但有趣的是equal_to从来没有被用做STL的默认比较函数。当STL中需要相等判断时,一般的惯例是直接调用operator==。比如,非成员函数find算法就是这么做的)

2.为包含指针的关联容器指定比较类型

why?第一条已经说明关联容器是要排序。每当你要创建包含指针的关联容器时,一定要记住,容器将会按照指针的值进行排序。一般是不是你希望的,所以你几乎要创建自己的函数子类作为该容器的比较类型。

3.总是让比较函数在等值情况下返回false

比较函数的返回值表明的是按照该函数定义的排列顺序,一个值是否在另一个之前。相等的值从来不会有前后顺序关系,所以,对于相等的值,比较函数应该始终返回false。

4.切勿直接修改set或multiset中的键。

5。考虑用排序的vector替代关联容器

在排序的vector中存储数据可能比在标准关联容器中存储同样的数据要耗费更少的内存,而考虑到页面错误的因素,通过二分搜索法来查找一个排序的vector可能比查找一个标准关联容器要更快一些。

6.当效率至关重要时,请在map::operator[]与map::insert之间谨慎做出选择

map::operator[]的设计目的是为了提供“添加和更新”的功能。添加一个新元素最好选后者insert。

7.熟悉非标准的散列容器。

posted @ 2014-05-16 16:30 Daywei 阅读(1305) | 评论 (0)编辑 收藏

仅列出标题  下一页
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

导航

统计

常用链接

留言簿

随笔分类

随笔档案

文章档案

牛人博客

搜索

积分与排名

最新评论

阅读排行榜