2008年12月29日 星期一

時間利用率非常低落

嗯,
說到最近,
說實在的,時間還蠻多的(因為,我感覺到我浪費很多時間)~

每每看到新聞還是網路上,
有人都非常認真到時間不夠~
就覺得實在非常心虛,
有時候今天讀不完,但是,常拿要保持作習正常來當藉口,
明天再把要讀的讀完~
常常這樣就沒有應有的進度~

另外,fuzzy的課,應該不會去上了~
因為,單單做一個模擬器不加上fuzzy的功能,就要非常多的時間,
我想這一個功能,若有學弟的話,就留給他們做吧~

人不是萬能的,不需要每一件事情都要自己做~

不過,我發現,我花很多時間在雜事上,每三十分鐘會開網頁或是bbs來看~
我現在實在很想早上到晚上六點之前在圖書館,然後,晚上六點之後才來實驗室~
說實在的,沒有電腦在的環境,我的讀書效率比較高~
想到準備研究所的那一段時間,其實我也是可以把時間利用的很好的~
加油!!

感覺是因為沒有給自己進度的壓力,所以,才會一直拖,由現在開始,要給自己明確的進度~

2008年12月28日 星期日

Qt - 在座標不動,放大縮小

為了要顯示無線網路的無線波,必需要知道如何讓空心圓在原地放大縮小。

因此,透過scale可以放大縮小整個圖的某一個元件。

在每一個GraphicsItem都有一個自己的座標系統,而放大縮小與旋轉都是依自己的座標系統的原點來決定的。

例如以下的程式碼:

QGraphicsEllipseItem *ball = new QGraphicsEllipseItem(0,0,30,30);

就是建立一個直徑為30pixel的圓,且其左上角剛好在自已的座標系統的(0,0)
若這個時候用放大的話,會依原點放大,所有,它會往右下角放大


QGraphicsEllipseItem *ball = new QGraphicsEllipseItem(-15,-15,30,30);

這個因為設定圖的左上角是在此小座標系統的(-15,-15),所以,(0,0)剛好是在圖的球心,這個時候放大,就會根據原點放大~

而把這一個放到QGraphicsScene的(0,0),則要在QGraphicsScene的函數中

MyScene::MyScene(qreal x,qreal y,qreal width,qreal height,QObject *parent):QGraphicsScene(x,y,width,height,parent) {
  QGraphicsEllipseItem *ball = new QGraphicsEllipseItem(-15,-15,30,30);
  addItem(ball); // 把這一個圓加入此QGraphicsScene中
  ball->setPos(this->width()/2,this->height()/2); // 設定球的小座標系統的左上角落在QGraphicsScene的(width()/2,this->height()/2)這一個位置
}

安裝Qt for XP and Ubuntu

在Ubuntu下安裝Qt有兩個方法
1. 透過apt-get

[user@host ~]$ sudo apt-get install qt4-designer qt4-doc qt4-dev-tools qt4-qtconfig

不過透過上面的方法,得到的版本是Qt4.3.2的版本

2. 到官方網站下載原始碼,自己編譯,這裡下載的是qt-x11-opensource-src-4.4.3.tar.gz
不過,若用此方法的話,要執行demo程式,直接打指令列qtdemo就可以啦

先解壓縮檔案吧~

[user@host ~]$ sudo tar -zxvf qt-x11-opensource-src-4.4.3.tar.gz


進入資料夾後

[user@host ~]$ ./configure -help

這樣會列出幾頁參數,可以調整一堆雜七雜八的安裝內容 ( 其實預設就差不多了 )。比較重要的是預設 -shared 會讓之後編譯 Qt 專案時產生較小 binary file,需要使用 shared library,沒有 library 的系統不能跑。
而 -static 則會包 runtime library 進去,不過檔案大小會增加很多。
-shared 和 -static 可以並存,但是需要個別 configure & make 在不同的資料夾 ( 用 -prefix 來設定安裝路徑 )。

確定後開始 configure
為了保持相容性,我基本上不會加上-no-qt3support

[user@host ~]$ ./configure -no-qt3support -optimized-qmake
[user@host ~]$ make

若出現X11/Xlib.h: No such file or directory
則要安裝libx11-dev
出現cannot find -lXext
則要安裝libxext-dev
(其實,這裡有一個偷吃步,先用sudo apt-get install qt4-designer qt4-doc qt4-dev-tools qt4-qtconfig,它會幫你安裝所有相依的套件,到時候再移除以上四個檔案,再用手動安裝目前這一個步驟)

[user@host ~]$ sudo apt-get install libx11-dev libxext-dev
[user@host ~]$ sudo make install


預設是用 -shared 裝在 /usr/local/Trolltech/Qt-4.3.1,編譯完之後大約為 410MB。-static 則約 1.2GB ( 因為每個 example application / demonstration 都會包 runtime library 進去... )。

安裝完成了,就要調校 $PATH 變數啦!免得 compile 時啥 header 都找無。
到.bashrc下加入這一行

PATH=/usr/local/Trolltech/Qt-4.4.3/bin:$PATH

完成啦~

在Windows XP安裝Qt
1. 在 http://www.bloodshed.net/devcpp.html 下載最新版的 Dev C++,直接下載含 MinGW 的版本
2. 在 http://trolltech.com/products/qt 下載 Qt 4.x Open Source (MinGW) for Windows
3. 安裝 Dev C++
4. 安裝 Qt 4.x,在 Previously installed MinGW 中設定 Dev C++ 的安裝位置
5. 開啟主控台,切換到 Qt 安裝目錄的 bin 目錄下,執行 qtvars.bat compile_debug 建置 Debug library,這要一些時間,去作些別的事吧!(這兩個選項可以在程式集下的Qt找到喔)
6. 要 make 寫好的程式,執行 qtvars.bat 可以幫你設好一些 Qt 所需的環境變數,以後要執行qmake,或make都必需要透過此qtvars.bar去執行
7. 另外,跑完之後,要把編譯過程中的檔案刪掉,就請到qtvars.bat執行make clean


參考資料:
在Ubuntu下安裝Qt
在Windows XP下安裝Qt

2008年12月27日 星期六

讓Qt程試碼可以在windows xp下執行

Qt是一個跨平台的函式庫,
然後,我希望我寫的程式可以在windows和linux下都可以跑~

在windows下安裝Qt請參考良葛格學習筆記

在linux下,寫好程式碼之後,
用qmake -project指定產生.pro檔,
再用qmake依.pro產生Makefile檔
再make編譯程式,就這樣,非常簡單

但是,在windows下,依上面的步驟,確出現錯誤,找不到檔案,
決解方法就是到Makefile.Debug在INCPATH的最後面加入所有我們自己所建立的header file的目錄…
例:

INCPATH = -I"c:\Qt\4.4.3\include\QtCore" -I"c:\Qt\4.4.3\include\QtCore" -I"c:\Qt\4.4.3\include\QtGui" -I"c:\Qt\4.4.3\include\QtGui" -I"c:\Qt\4.4.3\include" -I"." -I"c:\Qt\4.4.3\include\ActiveQt" -I"debug" -I"." -I"c:\Qt\4.4.3\mkspecs\win32-g++" -I"src\widget" -I"src\items"

後面藍色的部分就是我新增的部分~

解決!!

[2009.02.06] 補充
在觀查完linux與windows下的*.pro檔之後,知道為什麼會出現這一個問題了。
可能是windows下運行qmake -project的程式沒有寫好吧~
在windows下qmake -project下的*.pro的INCLUDEPATH的欄位只有 .

所以當然就找不到我所需要的header file啦~
只要在後面加上所有的header file的路徑即可,此問題只有在windows下用qmake -project會出現


TEMPLATE        = app
CONFIG          = qt warn_on release
DESTDIR         = ./             # 執行檔被建立後,擺放的位置
HEADERS         = miniwin.h      # 我們建立的class header
SOURCES         = miniwin.cpp \  # 我們建立的class主程式
main.cpp
INCLUDEPATH     += ./            # 指定include的路徑,例如/usr/local/xxx.h,則要加入/usr/local
DEPENDPATH      += ./            # 所有cpp檔案的路徑
LIBS            +=               # 指定要使用到的Library,應該是.so之類的動態library
INTERFACES      = 
TARGET          = miniwin        # 被建立的執行檔名稱


[2013.01.05 補充]
今天嘗試在Windows XP安裝Qt 4.8.4的流程如下:
先去下載MinGW Compiler for Windows,
因為,我們要下載的Qt 4.8.4是指定要MinGW 4.4 Compiler,
若用比較新的MinGW反而會有一些不預期的問題,
所以,要先去尋找MinGW 4.4,
不過,現在大部分官方網站都找不到MinGW 4.4,
我是直接用MinGW-gcc440_1.zip關鍵字在網路上尋找,
一下子就找到了。
下載頁面
下載之後,把它解壓縮到C:\MinGW

再來是安裝Qt,
Qt的下載頁面


下載完後,裡面就已經有編譯好的Demo的application,
如果要重新compiler成Open source的license的話,則必需要重新Compiler,則在
「開始」→「所有程式」→「Qt by Digia v4.6.4 (MinGW OpenSource)」→「Qt 4.6.4 (Build Debug Libraries)」
這樣會重新開始編譯所有demo的source code。

Build完之後,直接打qtdemo就可以執行demo的application了。

若一般的compiler自己的程式的話,則使用
「開始」→「所有程式」→「Qt by Digia v4.6.4 (MinGW OpenSource)」→「Qt 4.6.4 Command Prompt」
會把Qt的環境設定好。

Build code的流程請參考如何build出不需要另外建置環境的QT exe檔

QtCreator則是用Qt Creator 2.6.1的版本

可以完整編譯完qtdemo的組合
因為不像windows其它IDE一樣,全部都是包好的情況下,
所以,記錄一下整合的版本
[MinGW-gcc440_1.zip]
[qt-creator-windows-opensource-2.6.1.exe]
[qt-win-opensource-4.6.4-mingw.exe]

參考資料:
用QT建立一個基本視窗
windows上安装MinGW 4.4、Qt library 4.8.4和Qt Creator

2008年12月26日 星期五

Qt 資源系統

在qt4中,可以透過資源系統,把圖片嵌入到程式碼中。這樣圖片不見,也沒有關係啦~

Qt 資源系統(Resource System)可以提供與平台無關的機制,讓您把應用程式的圖檔、語系檔、資料等儲存於可執行檔之中,避免相關的資源檔案遺失的問題,Qt資源系統是基於 qmake、rcc(resource compiler),並搭配QFile來使用,您必須在產生的.pro檔之中,告知資源群集檔(Resource Collection File)的位置與名稱。

資源群集檔的副檔名為.qrc,實際的內容為XML格式的檔案,當中告知了這個應用程式所要使用到的資源檔案,例如您想要將QListWidget 與 QListWidgetItem 中所使用到的圖檔儲存在可執行檔案之中,則可以撰寫一個resourcefile.qrc:

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
  <file>images/bee_head.jpg</file>
  <file>images/bush_head.jpg</file>
  <file>images/cat_head.jpg</file>
  <file>images/caterpillar_head.jpg</file>
  <file>images/momor_head.jpg</file>
</qresource>
</RCC>

檔案的路徑是相對於.qrc檔案的位置。接著您要在產生的.pro檔案中,增加一行,告知.qrc檔案的位置,例如:
RESOURCES = resourcefile.qrc

qmake會產生出製造qrc_resourcefile.cpp的規則,之後使用rcc產生.cpp檔案,當中會將想要嵌入的相關檔案,壓縮並轉換為代表二進位資料的C++靜態無號字元陣列,如果您的.qrc檔案內容有變動,在編譯時.cpp檔案也會重新產生。

如果要使用嵌入的資源,則要在路徑的前端放置:/,例如:

QListWidget *listWidget = new QListWidget;
listWidget->insertItem(0, new QListWidgetItem(QIcon(":/images/caterpillar_head.jpg"), "caterpillar"));
listWidget->insertItem(1, new QListWidgetItem(QIcon(":/images/momor_head.jpg"), "momor"));
listWidget->insertItem(2, new QListWidgetItem(QIcon(":/images/bush_head.jpg"), "bush"));
listWidget->insertItem(3, new QListWidgetItem(QIcon(":/images/bee_head.jpg"), "bee"));
listWidget->insertItem(4, new QListWidgetItem(QIcon(":/images/cat_head.jpg"), "cat"));

您也可以為資源檔案的路徑設置別名(Alias),例如:

<file alias="caterpillar_head.jpg">images/caterpillar_head.jpg</file>

之後在程式中指定路徑時,就可以直接使用別名,例如:

listWidget->insertItem(0, new QListWidgetItem(QIcon(":/caterpillar_head.jpg"), "caterpillar"));

您也可以為別名設置前置(Prefix),例如:

<qresource prefix="/resources">
  <file alias="caterpillar_head.jpg">images/caterpillar_head.jpg</file>
</qresource>


之後每個別名都會自動加上前置,使用時如下:

listWidget->insertItem(0, new QListWidgetItem(QIcon(":/resources/caterpillar_head.jpg"), "caterpillar"));


您也可以搭配語系來使用嵌入的資源檔,例如若這麼設定:

<qresource>
  <file>caterpillar_head.jpg</file>
</qresource>
<qresource lang="zh_TW">
  <file alias="caterpillar_head.jpg">caterpillar_head_zh_TW.jpg</file>
</qresource>

當路徑指定為:/caterpillar_head.jpg,如果使用者是使用zh_TW語系,則會自動對應使用caterpillar_head_zh_TW.jpg,此一方法也可以用來載入.qm檔案,以實現多國語系支援,可參考 翻譯應用程式 與 多國語系選擇與切換。

參考資料:
Qt資源系統

全域變數

區域變數就是只能在一個區塊中被使用
例:

void foo1(){
int x=4;
cout << x << endl;
}

void foo2(){
cout << x << endl; // 出現錯誤
}

以上這一個例子的x就是區域變數,只能在foo1()內使用而不能在foo2()內使用。

而全域變數的例子呢

int x=4;
void foo1(){
cout << x << endl;
}

void foo2(){
cout << x << endl;
}

而以上的例子的x可以在foo1()與foo2()使用,而這就是全域變數。


#include <iostream>
#include <string>
using namespace std;

string color("red");

void local();

int main()
{
  extern string color; // 告知這一個變數宣告在別處,這裡是可以省略的,因為是在同一個檔案,若string color("red");是在其它檔案,而且我們沒有include進來,則這一行就是必要的
  cout << "Global color: " << color << endl;
  local();
  return 0;
}

void local()
{
  string color("blue");
  cout << "Local color: " << color << endl;
  cout << "Global color: " << ::color << endl;
}

透過::運算子告知,我要全域變數的color,而沒有加::的表示,選擇宣告比較近的那一個

2008年12月25日 星期四

exit()與return()的差別

在main函數中我們通常使用return (0);這樣的方式返回一個值。

但這是限定在非void情況下的也就是void main()這樣的形式。

exit()通常是用在例程中用來終結程式用的,使用後程式自動結束跳會作業系統。

但在如果把exit用在main內的時候無論main是否定義成void返回的值都是有效的,並且exit不需要考慮類型,exit(1)等價於return (1)

參考來源:
exit()與return()的差別

2008年12月23日 星期二

Qt3與Qt4共存

因為學長留下來的程式碼是Qt3寫的,
而其中主要用到的類別QCanvas我在Qt4中竟然找不到!

所以本來打算就繼續用Qt3改程式,但是,最近看了一下Qt4的demo程式,還有其中有興趣的程式碼,發現,其實,QCanvas的類別在Qt4中還是存在的,只不過它沒有顯示在主要的類別頁面中。

而且類別名稱也改成Q3Canvas的,所以,若真的要原來的程式碼可以在Qt4上跑的話,必須要把有改過的類別名稱都改成Qt4中新的名稱,不過,我不會做這樣的事情的!

所以,就想說把Qt4與Qt3共存~
在不確定是否能共存的時候,就只好先用vmware來作實驗啦~

在實驗之後,確定是可以共存的~
不過,有兩個情況,就是安裝Qt3與Qt4的順序。
在只有一個版本的時候,只會有一個qmake,但是,當有兩個版本之後,就會出現qmake-qt3與qmake-qt4。

當安裝完Qt3再安裝Qt4,此時的qmake是指到qmake-qt3
而若相反的話,則系統的qmake是指到qmake-qt4

若原本是指到qmake-qt3的話,要把它改到qmake-qt4的話使用以下指令,以下是建立一個qmake的捷徑是指到qmake-qt4

[root@host ~]# ln -T /usr/bin/qmake-qt4 /usr/bin/qmake

這樣就可以同時跑qt3和qt4啦~

若過透過qmake產生Makefile時,若是qt3則用qmake-qt3而qt4則使用qmake-qt4

2008年12月22日 星期一

event

Qt的事件跟Signal、Slot機制是不同的。
Signal與Slot的機制是同步的(Synchronous),Signal是由物件發出的,使用QObject的connect()連接物件上定義的Slot來立即處理。
Qt的事件可以是非同步的(Asynchronous)的,Qt使用一個事件佇列來維護,新的事件產生時基本上會被排到佇列的尾端,前一個事件處理完成,再從佇列的前端取出下一個佇列來處理,必要的時候,Qt的事件也可以是同步的,而事件還可以使用「事件過濾器」進行過濾處理。

跟網路要傳封包感覺很像,先學起來~

在qt3的教學文件中有一個部分範例
建立一個自定的事件

class ColorChangeEvent : public QCustomEvent
{
  public:
    ColorChangeEvent( QColor color ) : QCustomEvent( 346798 ), c( color ) {};
    QColor color() const { return c; };
  private:
    QColor c;
};


// To send an event of this custom event type:產生一個事件,並傳送給receiver

ColorChangeEvent* ce = new ColorChangeEvent( blue );
QApplication::postEvent( receiver, ce ); // Qt will delete it when done


// To receive an event of this custom event type:接收事件

void MyWidget::customEvent( QCustomEvent * e )
{
  if ( e->type() == 346798 ) { // It must be a ColorChangeEvent
    ColorChangeEvent* ce = (ColorChangeEvent*)e;
    newColor = ce->color();
  }
}


下面是我自己寫的一個例子
myevent.h

#ifndef MYEVENT_H
#define MYEVENT_H

#include <qevent.h>

class MyEvent:public QCustomEvent
{
  public:
    MyEvent(int );

    int value() const;
  private:
    int x;
};

#endif // MYEVENT_H


myevent.cpp

#include "myevent.h"

MyEvent::MyEvent(int y):QCustomEvent(346798),x(y){
  // do nothing
}

int MyEvent::value() const{
  return x;
}


mywidget.h

#ifndef MYWIDGET_H
#define WYWIDGET_H

#include <qwidget.h>
#include "myevent.h"

class MyWidget:public QWidget
{
  public:
    MyWidget(QWidget *parent,const char *name=0);

  protected:
    void customEvent(QCustomEvent *);

};

#endif // MYWIDGET_H


mywidget.cpp

#include "mywidget.h"

#include <iostream>
using namespace std;

MyWidget::MyWidget(QWidget *parent,const char *name):QWidget(parent,name)
{
  // do nothing
}

void MyWidget::customEvent(QCustomEvent *e){
  if (e->type() == 346798) {
    MyEvent *ce = (MyEvent *) e; // 透過父類別的子標變數接收,要強制轉換成子類別的子標
    cout << "有接收到事件啦" << ce->value() << endl;
  }
}


main.cpp

#include <qapplication.h>

#include "mywidget.h"

int main(int argc,char **argv)
{
  QApplication app(argc,argv);

  MyWidget w(0);

  MyEvent *m = new MyEvent(22);
  QApplication::postEvent(&w,m);

  w.resize(300,300);

  app.setMainWidget(&w);
  w.show();

  return app.exec();
}


C++事件(Event)機制的實現一例

2008年12月21日 星期日

struct

這裡說明一個struct的範例,並且初始化這一個struct


#include <stdio.h>

struct // 這一個結構沒有名稱,即匿名結構
{
  int id;
  char *path;
  int frames;
}
kas_animations [] = // kas_animations就是上面建立的結構,而下面就是初始化
{
  {01,"first",12},
  {02,"second",24},
  {03,"third",36}
}; // 記得要在最後加分號

struct person // 定義一個名為person的結構
{
char *first_name;
char *second_name;
};

int main()
{
  int i;
  for (i=0;i<3;i++){
    printf("id:%d\tpath:%s\tframes:%d\n",kas_animations[i].id,kas_animations[i].path,kas_animations[i].frames);
  }

  struct person ren = {"Fang","renyang"}; // 初始化一個person結構的ren變數,在c中必需要加struct,但是,在c++中可以省略
  printf("The first name is %s, and the second name is %s\n",ren.first_name,ren.second_name);
  return 0;
}



以下是純記錄別人網站的東西,以後搞不好有機會用到
C/C++語言struct深層探索
1. struct的巨大作用
面對一個人的大型C/C++程式時,只看其對struct的使用情況我們就可以對其編寫者的編程經驗進行評估。因為一個大型的C/C++程式,勢必要涉及一些(甚至大量)進行資料組合的結構體,這些結構體可以將原本意義屬於一個整體的資料組合在一起。從某種程度上來說,會不會用struct,怎樣用struct是區別一個開發人員是否具備豐富開發經歷的標誌。

在網路協定、通信控制、嵌入式系統的C/C++編程中,我們經常要傳送的不是簡單的位元組流(char型陣列),而是多種資料組合起來的一個整體,其表現形式是一個結構體。

經驗不足的開發人員往往將所有需要傳送的內容依順序保存在char型陣列中,通過指標偏移的方法傳送網路報文等資訊。這樣做編程複雜,易出錯,而且一旦控制方式及通信協定有所變化,程式就要進行非常細緻的修改。

一個有經驗的開發者則靈活運用結構體,舉一個例子,假設網路或控制協定中需要傳送三種報文,其格式分別為packetA、packetB、packetC:


struct structA
{
  int a;
  char b;
};

struct structB
{
  char a;
  short b;
};

struct structC
{
  int a;
  char b;
  float c;
}


優秀的程式設計者這樣設計傳送的報文:


struct CommuPacket
{
  int iPacketType; //報文類型標誌
  union //每次傳送的是三種報文中的一種,使用union;union有一點類似struct,只不過,每宣告一個變數,只能代表內容中的其中一個
  {
    struct structA packetA;
    struct structB packetB;
    struct structC packetC;
  }
};


在進行報文傳送時,直接傳送struct CommuPacket一個整體。

假設發送函數的原形如下:

// pSendData:發送位元組流的首位址,iLen:要發送的長度

Send(char * pSendData, unsigned int iLen);

發送方可以直接進行如下調用發送struct CommuPacket的一個實例sendCommuPacket:

Send( (char *)&sendCommuPacket , sizeof(CommuPacket) );

假設接收函數的原形如下:
// pRecvData:發送位元組流的首位址,iLen:要接收的長度
//返回值:實際接收到的位元組數

unsigned int Recv(char * pRecvData, unsigned int iLen);

接收方可以直接進行如下調用將接收到的資料保存在struct CommuPacket的一個實例recvCommuPacket中:

Recv( (char *)&recvCommuPacket , sizeof(CommuPacket) );

接著判斷報文類型進行相應處理:


switch(recvCommuPacket. iPacketType)
{
  case PACKET_A:
    … //A類報文處理
    break;
  case PACKET_B:
    … //B類報文處理
    break;
  case PACKET_C:
    … //C類報文處理
    break;
}

以上程式中最值得注意的是

Send( (char *)&sendCommuPacket , sizeof(CommuPacket) );
Recv( (char *)&recvCommuPacket , sizeof(CommuPacket) );
中的強制類型轉換:(char *)&sendCommuPacket、(char *)&recvCommuPacket,先取位址,再轉化為char型指標,這樣就可以直接利用處理位元組流的函數。

利用這種強制類型轉化,我們還可以方便程式的編寫,例如要對sendCommuPacket所處記憶體初始化為0,可以這樣調用標準庫函數memset():

memset((char *)&sendCommuPacket,0, sizeof(CommuPacket));

2. struct的成員對齊
Intel、微軟等公司曾經出過一道類似的面試題:


#include <iostream.h>
using namespace std;

#pragma pack(8)
struct example1
{
  short a;
  long b;
};

struct example2
{
  char c;
  example1 struct1;
  short e;
};

#pragma pack()

int main(int argc, char* argv[])
{
  example2 struct2;

  cout << sizeof(example1) << endl;
  cout << sizeof(example2) << endl;
  cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2) << endl;

  return 0;
}

問程式的輸入結果是什麼?

答案是:

8
16
4

不明白?還是不明白?下麵一一道來:

2.1 自然對界

struct是一種複合資料類型,其構成元素既可以是基本資料類型(如int、long、float等)的變數,也可以是一些複合資料類型(如 array、struct、union等)的資料單元。對於結構體,編譯器會自動進行成員變數的對齊,以提高運算效率。缺省情況下,編譯器為結構體的每個成員按其自然對界(natural alignment)條件分配空間。各個成員按照它們被聲明的順序在記憶體中順序存儲,第一個成員的位址和整個結構的位址相同。

自然對界(natural alignment)即默認對齊方式,是指按結構體的成員中size最大的成員對齊。

例如:

struct naturalalign
{
  char a;
  short b;
  char c;
};

在上述結構體中,size最大的是short,其長度為2位元組,因而結構體中的char成員a、c都以2為單位對齊,sizeof(naturalalign)的結果等於6;

如果改為:


struct naturalalign
{
  char a;
  int b;
  char c;
};

其結果顯然為12。

2.2指定對界

一般地,可以通過下面的方法來改變缺省的對界條件:

• 使用虛擬指令#pragma pack (n),編譯器將按照n個位元組對齊;
• 使用虛擬指令#pragma pack (),取消自定義位元組對齊方式。

注意:如果#pragma pack (n)中指定的n大於結構體中最大成員的size,則其不起作用,結構體仍然按照size最大的成員進行對界。

例如:


#pragma pack (n)
struct naturalalign
{
  char a;
  int b;
  char c;
};


#pragma pack ()
當n為4、8、16時,其對齊方式均一樣,sizeof(naturalalign)的結果都等於12。而當n為2時,其發揮了作用,使得sizeof(naturalalign)的結果為8。

在VC++ 6.0編譯器中,我們可以指定其對界方式,其操作方式為依次選擇projetct > setting > C/C++功能表,在struct member alignment中指定你要的對界方式。

另外,通過__attribute((aligned (n)))也可以讓所作用的結構體成員對齊在n位元組邊界上,但是它較少被使用,因而不作詳細講解。

2.3 面試題的解答

至此,我們可以對Intel、微軟的面試題進行全面的解答。

程式中第2行#pragma pack (8)雖然指定了對界為8,但是由於struct example1中的成員最大size為4(long變數size為4),故struct example1仍然按4位元組對界,struct example1的size為8,即第18行的輸出結果;

struct example2中包含了struct example1,其本身包含的簡單資料成員的最大size為2(short變數e),但是因為其包含了struct example1,而struct example1中的最大成員size為4,struct example2也應以4對界,#pragma pack (8)中指定的對界對struct example2也不起作用,故19行的輸出結果為16;

由於struct example2中的成員以4為單位對界,故其char變數c後應補充3個空,其後才是成員struct1的記憶體空間,20行的輸出結果為4。

3. C和C++間struct的深層區別
在C++語言中struct具有了“類” 的功能,其與關鍵字class的區別在於struct中成員變數和函數的默認訪問許可權為public,而class的為private。

例如,定義struct類和class類:


struct structA
{
  char a;
  …
}
class classB
{
  char a;
  …
}

則:

struct A a;
a.a = 'a'; //訪問public成員,合法
classB b;
b.a = 'a'; //訪問private成員,不合法
  許多文獻寫到這裏就認為已經給出了C++中struct和class的全部區別,實則不然,另外一點需要注意的是:

  C++中的struct保持了對C中struct的全面相容(這符合C++的初衷——“a better c”),因而,下面的操作是合法的:


//定義struct
struct structA
{
  char a;
  char b;
  int c;
};
structA a = {'a' , 'a' ,1}; // 定義時直接賦初值


即struct可以在定義的時候直接以{ }對其成員變數賦初值,而class則不能,在經典書目《thinking C++ 2nd edition》中作者對此點進行了強調。

4. struct編程注意事項
看看下面的程式:


#include <iostream>
using namespace std;

struct structA
{
  int iMember;
  char *cMember;
};

int main(int argc, char* argv[])
{
  structA instant1,instant2;
  char c = 'a';

  instant1.iMember = 1;
  instant1.cMember = &c;

  instant2 = instant1;

  cout << *(instant1.cMember) << endl;

  *(instant2.cMember) = 'b';

  cout << *(instant1.cMember) << endl;

  return 0;
}

14行的輸出結果是:a
16行的輸出結果是:b

Why?我們在15行對instant2的修改改變了instant1中成員的值!

原因在於13行的instant2 = instant1賦值語句採用的是變數逐個拷貝,這使得instant1和instant2中的cMember指向了同一片記憶體,因而對instant2的修改也是對instant1的修改。

在C語言中,當結構體中存在指標型成員時,一定要注意在採用賦值語句時是否將2個實例中的指標型成員指向了同一片記憶體。

在C++語言中,當結構體中存在指標型成員時,我們需要重寫struct的拷貝構造函數並進行“=”操作符重載。

轉載自CSDN

Qt Runtime Installer for Windows

若我在a這一台電腦寫出一個程式,但是,想要在b這一台電腦上跑,
但是,有一堆函式庫沒有在b這一台電腦上,
這個時候就要安裝Qt runtime for Windows

雖然目前都在linux下寫qt,但是,這個資料先留下來吧~

DLL List

  • Qt3Support4.dll
  • QtAssistantClient4.dll
  • QtCore4.dll
  • QtDesigner4.dll
  • QtDesignerComponents4.dll
  • QtGui4.dll
  • QtNetwork4.dll
  • QtOpenGL4.dll
  • QtScript4.dll
  • QtSql4.dll
  • QtSvg4.dll
  • QtTest4.dll
  • QtXml4.dll


參考資料:
Qt Runtime Installer for Windows

2008年12月20日 星期六

日本報告之行~

最近剛從日本報告回來~
第一次出國,還好是跟團出去,就是一群要去Conference的人一起組個團,
因為這次的報告,所以,10月底開始就在準備要報的這一個paper,
因為,跟我的之後要做的論文沒有什麼關係,所以,這算是額外花的時間。
去日本五天四夜還不錯玩~12/10-12/14

我是跟一個高應大的電子系博班是室友,
跟他討論到老師的問題,
他也說老師也沒有辦法真的教他們東西~
東西也是要自己學~

研究所跟大學最大的不同就是沒有人會教你~
大部分要自己學~

而現在我最主要的困難是有很多蠻基礎的東西我之前沒有學過,
所以要另外花時間去學~
但是,就是因為太多東西要學,又不知道從哪裡開始學~

像是我要寫的論文中,打算寫一個車用模擬器,來收集我針對某一台中的開車行為,
然後,透過fuzzy來學習,使得這一台車的行為模式就是我~
所以,我必需要學
fuzzy」:這一個學期有去旁聽,但是,還蠻理論的,覺得我可能只需要實作的部分就好
C++」:耶~算是看的差不多了,常用的東西都應該ok吧,就算不熟,查一下應該就有了,這個應該是寫程式最基本要會的
Qt」:因為Qt是C++的延申,而且,有很多API,再來要透過它展示我的模擬器,現在有一個問題是學長寫的模擬器是用Qt3寫的,而現在最新的是Qt4,而模擬器中最主要的Canvas類別在Qt4中竟然沒有了,所以,最近在找Qt4是否有取代QCanvas的類別,似呼有看到一個例子是動畫的,就是QCanvas的主要功能,近期要研究一下
軟體工程UML」:寫程式人人會,但是,要如何寫出一個可以讓後面的人好維護的程式,這才是一個課題,若不需望rework這麼多,code的重覆使用性就好高,所以,規畫要清楚
英文」:英文很重要,不用多說,現在每一天都會讀5個單子本的句子。
DSRC規格書」:因為,要做車間通訊,所以,還是要讀這一個spec,想起來就頭大

「Linux」:因為前景看好,我還喜歡打指令的~這想感覺好像是MIS喔

「PHP」:可以自己架站,因為,活用性比較高,可以收集很多自己的資料,就可以不用靠blogger,沒有空間上的上限啦~不過,要另外,維護的成本

分析:基本上因為,現在不景氣,所以,就算隨便畢業,出去也一定找不到工作。我是打算好好寫這一個模擬器,並且用軟體工程的方法好好規畫一下,用這一個模擬器來demo,到時候讓公司知道我有規畫的能力,而不是只會coding,若是只會coding,那真的只是在做coding黑手而以。當一個新的IDE出來,寫程式會比你更快,更好~重點是要會規畫~就像html現在用frontpage隨便拉都比十年前寫出來的還要漂亮。

目前還蠻想打算先放棄fuzzy,先把沒有fuzzy的模擬器先寫出來,以後,再把fuzzy的部分再加上去~但是,一直沒有那一個勇氣(基本上這樣應該要三年,但是,若三年真的可以把實力打的紮實,其實也是ok的)~

人生那麼長,有時候多個一年去好好把底子打好是相對值得的。比直接去公司,若公司訓練不好,都只是做雜事,那會更浪費時間~

真的要好好想一想~do it small, do it right

照片


2008年12月2日 星期二

三抓三放 時間用在刀口上!

作者/ 台大化工研究所教授 呂宗昕

捨棄一切的無關緊要
每天都從「專心去做最重要的事」開始,有一天,你也會向比爾蓋茲一樣成功。

你經常需要搶時間工作嗎?工作好像總是做不完?成天被客戶、老闆追跑?
待辦文件堆積如山?如果你正為這些問題困擾,「時間管理」是最佳解決之道

管理大師彼得‧杜拉克 (Peter Drucker) 說過:
「時間是世界上最短缺的資源,除非善加管理,否則一事無成。」

每個上班族都可望時間。我們需要時間處理辦公室內應做之事,也需要時間在繁忙與休閒生活間取得平衡。即使每個人對時間的冀求如此強烈,但實際上多數人對時間管理的概念都十分模糊,更何況無論學校教育或職前訓練,都未曾教過這重要的一課。

天資聰穎者在職場中,藉著經驗累積及失敗的歷練,可以在跌跌撞撞中順利摸索出掌握時間的訣竅;天資平庸者即使經歷挫敗,也未必能適時調整方向,領悟出適合自己的時間應對模式。

管理,全靠「學習」與「練習」

其實,時間管理是需要學習的,正如同你過去曾努力學習任一專業技能與科目一樣

時間管理也需要練習,在明瞭相關原則與技巧之後,必須身體力行、加以實踐才能為自己「搶」得寶貴的時間。

有一次,和某家電子公司總經理晤談時,他提到對於龐大的企業體而言,提高營運績效是終極目標,而他自己的首要目標是簡化工作。

那次談話讓我深有所感。
比爾蓋茲大概是科技業最忙碌的總裁之一,他年輕時就已懂得要跟時間賽跑。
他熱愛電腦,尚未自哈佛大學畢業,就迫不急待地在車庫裡創業。創立微軟那年,還未滿20歲。
在創業最初的7年裡,他只休15天假。比爾蓋茲認為工作是一場競賽,他喜歡在緊要關頭全力以赴的感覺,也深深享受伴隨而來的快樂與成就感。

他勇於追逐時間,結果打造出有史以來最強大的電腦軟體王國,為全世界數以億計的人們提供工作上的幫助及便捷。
他最喜歡的是電腦,最想積極擁抱的是高科技,所以才心甘情願,將絕大部分時間資源,都投注電腦科技。

深入瞭解比爾蓋茲的故事後,可將他的成功歸因於3大要素:

1.設立明確目標

他知道電腦是明日科技的夢想,也深信自己就是實現那夢想的人。
在心中訂立明確工作目標,設定清楚的工作藍圖,詳細規劃工作進度,就義無反顧努力追夢。

2.集中焦點攻擊

「Focus」這個單字是名詞,也是動詞。名詞是指焦點,動詞則是指集中焦點,比爾蓋茲將精力及時間全部投注在電腦科技的研發,集中焦點猛力攻擊,所以能在短時間內締造驚人的卓越成果。

3.簡化工作內容

比爾蓋茲一心一意專心經營他的軟體王國,無暇兼顧其他事務。他大幅簡化工作內容,使自己可以心無旁鶩地專於本業。工作簡化,讓他能專心思考,大幅減少無謂的時間浪費,進而獲得關鍵性的勝利。

「電視冠軍」節目曾介紹一位「水果達人」他為了讓果樹結出最碩大、最甜美的果實,總在果樹開花後摘掉大部分花朵,僅留兩、三個花苞。(這技術在農業上被稱為「疏果」)

「這樣不就會使果實產量大減嗎?」訪問者不解地問。
「我要讓全部養分都灌注在這幾個花苞上,這樣自然能夠結出最大、最甜的果實。」
達人自信滿滿地說。
水果達人的秘訣非常值得我們參考。

為自己的生活大樹 進行疏果

如果把樹木的主樹幹比喻為本業工作的話,那些旁生的細小枝幹就可能相當於瑣碎的雜務、不具意義的是、冗長無聊的會議、徒具表面功夫的人際交往等。以「時間養分」來說,這些細小枝幹與主樹幹是競爭者,所有養份將悉數灌注在主樹幹上,可使樹幹迅速拔高,成為頂天立地、高聳入雲的大樹。

我非常同意那位總經理的看法。工作必須適當簡化,有限的時間資源才能被有效利用。
我本身在忙碌生活中,也是利用簡化工作的概念,替自己爭取更多時間。

該如何簡化工作?「三抓三放」原則可供參考:

1.抓大事,放小事

集中思考工作上的大事,對於微不足道的小事,無須過度煩心。
高階管理者必須為公司明確定位,掌握未來發展的重要方向,別為枝微末節而操心;
基層員工應將時間用於可明顯提升業績的事務上,無關緊要的小事則盡量刪除。

2.抓正事,放雜事

要順利完成一件工作,有必要的程序及步驟,也就是完成任務的正事,而與完成任務無關的則稱為雜事。

一個有智慧的工作者應抓緊正事,將心力和時間集中投資於處理與該任務最相關的核心問題;至於與正式無關的雜事,可交由旁人處理,或是盡量避免,以簡化工作內容。

3.抓要事,放閒事

重要又緊急的事情應該再第一時間完成;
沒有時間壓力的閒事,則利用工作空檔,簡單處理即可。
要事與閒適的差別,在於對績效的貢獻度以及時間的緊迫程度
高績效貢獻度、高時間緊迫性的要事必須優先處理,
低績效貢獻度、低時間緊迫性的閒事則可暫緩或刪除。

比爾蓋茲之所以能夠成功,是因為他熱愛電腦,也熱愛時間。

如果你也希望再事業上有一番大成就,就請抓住主幹,放棄枝幹,
有一天你也會成就大事業。

本文摘自《30雜誌》10月號