2010年12月30日星期四

在main之前运行代码

我们学习C语言编程的时候老师都告诉我们程序从main函数开始执行,main返回时也代表程序结束。那么能否在main函数执行前运行一些代码呢,当然可以,虽然没多大意义。演示代码如下:

#include

class outNum{
public:
outNum()
{
int a;
std::cin>>a;
std::cout< }
};
int run()
{
std::cout<<"runn";
return 0;
}
int main()
{
std::cout<<"beginn";
return 0;
}
outNum a;
int m=run();


上面代码运行后先执行outNum对象的创建,无参数构造函数要求输入一个整形值,比如我们输入22后运行结果如下:

22
22
run
begin

记得以前哪本书上提到过在main运行前进行一些验证什么的。在这里用示例代码和大家分享一下。

2010年12月29日星期三

洛阳灾害天气个例管理平台

软件主界面如下所示


程序主界面
点击左下方的四个按钮可以切换筛选框的分类依据,比如点击按年份后,筛选框将出现从当年开始的逆序年份排列,选择某一年就可查看选定年份的灾害个例

2010年12月27日星期一

wxWidgets 多平台开发心得

不得不承认C++跨平台开发是有一定难度的,即使有wxWidgets这么好的库。


首先要考虑文件系统方面的差异:



  • 1.Ubuntu下面C++的源代码使用UTF8无BOM格式,换行符为n, 而在XP下面则为ansi编码,换行符为rn,源代码要进行转换。

  • 2.Ubuntu下面路径分隔符为/,而xp下面则为, 一定要注意在字符串中此字符表示为"",可以用wxFILE_SEP_PATH宏统一起来


其次是一些函数不同平台下实现细节的差异



  • 1.在ubuntu下获取Report格式的listctrl某一列的text 代码如下

    wxListItem info;
    info.SetId(row);
    info.SetColumn(col);
    list->GetItem(info);

    而在xp中必需在list->GetItem(info) 之前设置item的text码:info.SetMask(wxLIST_MASK_TEXT);

  • 2.wxDC类中设置放大系数和正负逻辑方向的一些不同,参见以前的有关讨论。


2010年12月14日星期二

wxWidgets中定时器(wxTimer)的使用

最简单的例子:



class MyFrame : public wxFrame
{
public:
...
       void OnTimer(wxTimerEvent&amp; event);

private:
       wxTimer m_timer; //定义 wxTimer对象
};

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_TIMER(TIMER_ID, MyFrame::OnTimer) //绑定事件处理函数
END_EVENT_TABLE()

MyFrame::MyFrame()
: m_timer(this, TIMER_ID) //绑定此对象到this并指定TIMER_ID
{
       m_timer.Start(1000); // 设置1秒间隔,并启动它
}

void MyFrame::OnTimer(wxTimerEvent&amp; event)
{
     // 在下面写需要执行的代码
}

C++ 继承类调用父类的函数

代码如下所示:


#include <iostream>

class A
{
protected:
int m;

public:
A(){ m = 0; }
void put()
{
add();
std::cout<<m<<std::endl;
}

void add()
{
m += 1;
}
};

class B:public A
{
public:
void add()
{
m += 2;
}
};

int main()
{
A a ;
B b ;
a.put();
b.put();
}


编译后运行结果是什么呢, 1   1  还是1   2呢?

正确答案是1     1,类B继承自A,执行 b.put() 时实际上是运行了A::put(),所以会调用 A::add() 而不是 B::add();

2010年10月26日星期二

洛阳一年中日平均温度的变化

统计了一下历年的资料,洛阳地区的日平均气温最低的时间出现在1月10号前后,大约为–3度,最高的时间出现在6月25号前后,大约为30度。

可以用以下公式来计算:

6月25号之前: Τ = 17*sin(π(d-92)/165) + 14        (i)

6月25号之后: Τ = 17*cos(π(d-175)/200) + 14   (ii)

其中π代表圆周率 可取3.14   ,d代表一年中的第几天,如5月1号是一年中的第121天,代入公式 (i)可计算出日平均温度大概为23度。

以上分析的是一年中温度的平均升高或降低情况,虽然每年的5月1号日平均温度会不同,但平均来说是23度。

2010年10月25日星期一

Micaps 资料复制工具

软件说明:


1.  此软件可按照日期(如2010年9月至10月)或者要素(如云图、地面图、高空图等)将Micaps资料复制到另一个文件夹,并且保持资料的目录结构不变,例如之前在high目录下的资料复制后依然在high目录下。

2. 左上方选择Micaps资料所在目录,右上方选择需要复制到的目录

3.   此软件无需安装,直接运行即可

4.  软件可跨平台,需要Linux下面的软件请联系我

软件截图


Micaps资料复制软件截图

点此下载

2010年10月21日星期四

递归删除目录下的VC临时文件

从网上找来的bat命令:

@echo off
@echo SDK开发包瘦身批处理
del *.pch /q /s
del *.obj /q /s
del *.ilk /q /s
del *.exp /q /s
del *.pdb /q /s
del *.idb /q /s
del *.ncb /q /s
del *.opt /q /s

rem 删除浏览信息文件
del *.sbr /q /s

rem Build Log文件
rem del *.plg /q /s

rem del *.aps /q /s

rem 删除临时文件
rem del *.tmp /q /s

rem 删除项目中存在的超大cache文件
del *cache.dat /q /s

rd *debug* /q /s
rd *release* /q /s
@echo 瘦身完成,请使用windows查找方法删除debug和release目录!
@pause

将以上命令复制到文本文件中,重命名为clear.bat,放到需要清除的目录下。然后在命令行下运行即可。

大家可根据需要增加或删除命令。比如需要删除所有该目录及子目录下的exe文件,可增加一条语句del *.exe /q /s

其中del命令的作用是删除文件 /q 选项指定为安静模式,删除时不需要确认,/s 选项指定递归删除,删除该目录及所有子目录下的exe文件。

rem命令指定该行是注释行

rd命令作用为删除目录

2010年10月13日星期三

欧洲格点预报显示软件

软件说明:


1.   此软件可以图形和表格方式显示Micaps资料中的欧洲7天格点预报

2.  直接运行软件,编辑软件目录下的 .ini 文件配置EC资料所在的路径 如 file_path=w:/ecmwf/

3.   此软件无需安装,直接运行即可

4.  软件可跨平台,需要Linux下面的软件请联系我

软件截图:



点此下载 欧洲预报格点显示

使用wxWidgets时发现的一些bug及解决方案

Ubuntu中

wxDC类

bug 1.  使用SetLogicalOrigin时必须确保坐标轴为默认方向(SetAxisOrientation(true,false)),使用后可更改为需要的方向(SetAxisOrientation(true,true));

解决方案:查看wxGTK源代码文件dc.cpp可看到如下代码:

void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
{
m_logicalOriginX = x * m_signX; // is this still correct ?
m_logicalOriginY = y * m_signY;
ComputeScaleAndOrigin();
}

作者也察觉到了这里可能有问题,标注了// is this still correct ?


将上面代码修改如下即可:



void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
{
m_logicalOriginX = x ;
m_logicalOriginY = y ;
ComputeScaleAndOrigin();
}

bug 2. 使用SetUserScale函数设置放大倍数时画笔(wxPen)的宽度随之放大,但在xp系统下画笔宽度不变。也就是说如果设置SetUserScale(1,1000),则画笔宽度可能变为1000像素,导致无法成功绘制图像。

解决方案:从源代码文件dc.cpp中我们可以看到SetUserScale函数的定义:

void wxDC::SetUserScale( double x, double y )
{
// allow negative ? -> no
m_userScaleX = x;
m_userScaleY = y;
ComputeScaleAndOrigin();
}

在源代码文件dcclient.cpp中我们可以看到wxWindowDC::ComputeScaleAndOrigin()函数的定义:



void wxWindowDC::ComputeScaleAndOrigin()
{
const wxRealPoint origScale(m_scaleX, m_scaleY);

wxDC::ComputeScaleAndOrigin();

// if scale has changed call SetPen to recalulate the line width
if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.Ok() )
{
// this is a bit artificial, but we need to force wxDC to think the pen
// has changed
wxPen pen = m_pen;
m_pen = wxNullPen;
SetPen( pen );
}
}

进一步我们可以找到函数 wxWindowDC::SetPen 的定义



void wxWindowDC::SetPen( const wxPen &pen )

{

wxCHECK_RET( Ok(), wxT(“invalid window dc”) );
if (m_pen == pen) return;
m_pen = pen;
if (!m_pen.Ok()) return;
if (!m_window) return;

gint width = m_pen.GetWidth();
if (width <= 0)
{
// CMB: if width is non-zero scale it with the dc
width = 1;
}
else
{
// X doesn’t allow different width in x and y and so we take
// the average
double w = 0.5 +
( fabs((double) XLOG2DEVREL(width)) +
fabs((double) YLOG2DEVREL(width)) ) / 2.0;
width = (int)w; //注意,这个宽度是最终绘制的宽度
if ( !width )
{
// width can’t be 0 or an internal GTK error occurs inside
// gdk_gc_set_dashes() below
width = 1;
}
}

//…… 中间的代码省略

gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );

m_pen.GetColour().CalcPixel( m_cmap );

gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );

}

综合以上代码分析我们可以看到:当我们调用函数SetUserScale 放大绘制的图形时,wxGTK同时放大了绘制线条的宽度。


解决办法是删除 width = (int)w;  这行代码。



修改源代码后,重新编译wxGTK即可。



XP中

wxDateTime

bug 1. wxDateTime::Format 函数不支持中文字符的格式化。

解决方案:暂时可以使用wxString::Format函数替代。

2010年9月16日星期四

字符编码的转换(C++为例)

出处:http://www.cppblog.com/chemz/archive/2007/05/30/25133.html

内容如下:

字符集相关问题
字符集目前有两个大的类别:本地字符集和国际字符集,其中每一类别的字符集又有多个
不同的字符编码实例。比如:本地字符集中基本上对于每一个不同的地区和国家就会形成一个
属于自己的字符集(ascii, latin-1, chs等),国际字符集中同样包括多种不同的编码方案
(utf8, utf16等)。
那么在C/C++程序中如何完成上述字符集之间的转换工作呢?分成两种情况:
1. 通过const char *cstr使用开发环境中的编辑器输入字符串常量"中国",如下:
const char *cstr = "中国";
这样一来cstr所指向的字符串内存中保存的则是本地字符编码下所形成的字符串,也
就是说,上面的cstr中存储着chs字符编码集中的字符;
2. 通过const wchar_t *wstr使用开发环境中的编辑器输入字符串常量"中国",如下:
const wchar_t *wstr = L"中国";
这样一来wstr所指向的字符串内存中保存的则是国际字符编码(在VC++下是ucs2,
在gcc下是ucs4)下所形成的字符串,也就是说,上面的wstr中存储着utf16字符编
码集中的字符;
那么如何将cstr转换成为wstr呢?可以通过C语言中的标准转换函数mbstowcs来完成该工
作,此时需要注意的是如果直接使用mbstowcs进行转换会得到一个错误的结果,并不能成功
的完成转换成为国际宽字符的要求,这是为什么呢?在C/C++语言标准中定义了其运行时的
字符集环境为"C",也就是ASCII字符集的一个子集,那么mbstowcs在工作时会将cstr中所包
含的字符串看作是ASCII编码的字符,而不认为是一个包含有chs编码的字符串,所以他会将
每一个中文拆成2个ASCII编码进行转换,这样得到的结果就是会形成4个wchar_t的字符组成
的串,那么如何才能够让mbstowcs正常工作呢?在调用mbstowcs进行转换之间必须明确的告
诉mbstowcs目前cstr串中包含的是chs编码的字符串,通过setlocale( LC_ALL, "chs" )函数
调用来完成,需要注意的是这个函数会改变整个应用程序的字符集编码方式,必须要通过重
新调用setlocale( LC_ALL, "C" )函数来还原,这样就可以保证mbstowcs在转换时将cstr中
的串看作是中文串,并且转换成为2个wchar_t字符,而不是4个。

程序乱码的根源(C++为例)

当字符以某种编码(例如gbk)存储,但是以另一种编码(例如utf-8)显示时,乱码就产生了。

例如以下的C++源代码
//file1.cpp

#include
int main()
{
char str[100]="abc完美";
std::cout<<str;
}


当编译链接后,程序在控制台(终端)一定会显示 abc完美 这几个字符么,不一定。

首先要看源代码file1.cpp是采用什么编码方式存储的,假如是GBK编码方式,则编译后生成的可执行文件中存储的是"abc完美"的GBK码。

其次要看系统的默认编码是什么,简体中文Windows的系统默认编码是GBK,Ubuntu 10的系统默认编码是UTF-8。当执行程序时,系统会用默认的编码显示字体。

具体来说,如果file1.cpp是用GBK编码方式,则字符串"abc完美"也将以GBK编码存储在可执行程序中,在简体中文Windows中运行程序时,系统将以默认的GBK编码解读字符串,于是正确显示字符串"abc完美";但是当在Ubuntu 10中运行程序时,系统也将以默认的UTF-8编码解读字符串,由于用以存储和显示字符串的编码方式不一致,于是乱码产生了。

所以如果不考虑跨平带和国际化的话,源代码要以系统默认的编码方式存储,这样可以避免乱码的产生。对于初学者,这应该是比较简单实用的方式。

相关讨论

1.  所见非所得-C++的代码编码(Encoding)

2. 避免在cpp源文件中出现静态的中文文字常量

3. 字符集及字符的显示

2010年8月27日星期五

ubuntu 安装小记

从来没有想到ubuntu的安装会这么简单。


像大多数人一样我之前用的是xp系统,在安装ubuntu之前不想离开xp,何况电脑上还有大量数据,迁移起来会是不小的工程,于是就想着先把E盘分为两个盘,然后在F盘上安装ubuntu。下面是今天安装的过程。



  • 1. 在google上搜索并下载了两个磁盘分区软件,准备把E盘的空闲空间分为F盘,结果折腾了有一个多小时都没有成功,分区软件运行一会就没反应了,试了几次都是这样,E盘系统也有些损坏,害我用xp自带的文件系统修复命令修复了一遍,幸亏E盘数据没有丢失。看来这个方法行不通。

  • 2. 在网上搜索了大量xp系统上安装ubuntu的文章,说的都比较简单,于是就想着不管那么多了,直接在E盘上安装算了,如果数据丢失了也不要紧,反正都是电影音乐图片之类的文件。

  • 3.从网上下载了ubuntu-10 iso镜像文件 和 一个免费刻盘软件BurnAware Free 并刻盘。

  • 4.电脑光盘启动,接下来就是ubuntu非常人性化的图形安装界面,每一步都非常简单,选择语言、选择时区、选择键盘方式。

  • 5. 最关键一步的是选择分区那一步,选择自定义分区,然后选择E盘,增加一个不做任何操作的分区,ubuntu会自动将E盘以前的数据迁移. 接下来增加一个2G的邏辑分区给交换空间,然后增加一个20G的主分区并选择EXT4日志文件系统.

  • 6. 就是这些了,接下来按照ubuntu默认安装就行了.

  • 7.安装完成后进入ubuntu, 你会惊讶地发现,在ubuntu里面竟然可以查看并修改之前xp上面的文件.


所以,所以这么简单,快迁移到ubuntu上面来吧,一样有图形用戶界面,最关健的是速度飞快.

关于编程中double类型的比较

相信很多人编程的时候都会像下面这样比较两个double类型吧:


double a=1/2, b=0.5;

if(abs(a-b)<1e-6)
{
cout<<"a==b";
}


当然这个是可以的,但是为什么不直接用 if(a==b) 这样子呢,因为书上好像说过不能直接用等号比较double类型,因为double在计算过程中有精度损失。

其实是我们理解错了,书上说的是在复杂的计算过程后,比如 double result = 3/7/5*7*5,在这之后,resule == 3 可能不一定成立,因为result可能等于2.999999999。但是如果我们仅仅是比较两个简单的double类型,那么完全可以用等号(==),比如 最开始的if表达式可以写成if(a==b),这样没有任何问题的。假如a==b不能比较,那a>b,a<b等也不能比较了,显然不是这样的。

2010年8月24日星期二

2010年1月12日星期二

C++ 命名空间 变量声明 定义

终于明白了C++的命名空间中变量声明的问题 正确方式为在头文件中声明如下: namespace A { extern int a;} 在cpp文件中定义如下:namespace A{int a=100;}

C++ 编码转换 多字节字符 宽字符

C++ 中可用的字符编码总体上说有两种: 一种为多字节字符, 如Ansi编码,每个汉字由2个char 确定,或者utf-8编码,每个汉字由三个char 确定。另一种为宽字符编码,每个汉字直接由1个short(wchar_t)确定。


自己利用两个Win32 API函数写了两个用于编码转换的函数



//编码转换

#include

#include

//UTF8编码转换为Ansi编码
std::string & Utf8ToAnsi(std::string &scr, std::string &des)
{
size_t n = scr.size()*2;
wchar_t *sl = new wchar_t[n];

char *sm = new char[n];
//多字节(UTF8)编码转换为宽字节编码
MultiByteToWideChar(CP_UTF8,0,scr.c_str(),-1,sl,n);

//宽字节转换为多字节(Ansi)编码
WideCharToMultiByte(CP_ACP, 0,sl, -1,sm, n,NULL,0);

des = sm;
delete []sl;
delete []sm;

return des;
}

//Ansi编码转换为Unicode(Utf16)编码
std::wstring & AnsiToUtf16(std::string &scr, std::wstring &des)
{
size_t n = scr.size();

wchar_t *sl = new wchar_t[n+1];

MultiByteToWideChar(CP_ACP,0,scr.c_str(),-1,sl,n+1);

des = sl;
delete []sl;

return des;
}