在 C++ 顯示完整的 typeid 型別名稱

在 C++ 裡面,如果需要知道一個型別的資訊,基本上可以使用 typeid() 這個運算子(文件)來取得 std::type_info文件)的物件、然後他還有提供 name() 這個函式,可以用來取得型別的名稱。

所以,在一般的情況下,如果要知道一個型別的名稱,可以使用下面的形式來做:

#include <iostream>
#include <tuple>
 
int main()
{
  std::cout
    << "float: " << typeid(float).name() << "\n"
    << "tuple: " << typeid(std::tuple<int, double>).name() << "\n"
    << std::endl;
}

閱讀更多»

解決 g++ 連結程式時的循環相依性的問題

在寫 C++ 的程式的時候,如果有拆分模組,有的時候會導致不同模組/函式庫之間的相依性變得很複雜、甚至可能會產生彼此互相相依的狀況(circular dependencies、維基百科有提供例子)。

在 Visual C++ 的環境下,linking 階段似乎是沒有順序、而且不會因為連結的順序、導致找不到參考的狀況。

但是在 g++ 的環境下,由於他的連結是有順序性的,所以如果加上 -lXXX 的順序不對,就可能會出現找不到參考的問題(錯誤訊息是「undefined reference」)。
比如說如果 libA 有用到 libB 的函式的話,那在連結的時候,libA 就必須要在 libB 的前面。

閱讀更多»

不使用 qmake 建置 Qt Designer 產生的程式:GNU Make

前一篇《不使用 qmake 建置 Qt Designer 產生的程式:手動建置》基本上已經講了要怎樣手動建置一個 Qt 的應用程式了;而這一篇,則是來寫一個 Qt 應用程式的 GNU Make(參考:維基百科)的 Makefile 了~

這邊同樣是使用上次那個 QtTest 的範例。而對應的 Makefile,由於 Heresy 個人對於 Makefile 的撰寫沒有很深的研究,在弄了很久之後,最後是寫成下面的形式:

 1.  QTTMP_PATH      = ./generated/
 2.  INC_PATH        = -I. \
 3.                    -I$(QTTMP_PATH) \
 4.                    -I/usr/include/qt4
 5.  LIB_PATH        = -L/usr/lib/qt4
 6.  QTLIBS          = -lQtCore -lQtGui -lQtOpenGL
 7.
 8.  .SUFFIXES:
 9.  .SUFFIXES:      .cpp .o .hxx .qrc .ui .hpp
10.
11.  QTCOMPILE_FILES = $(QTTMP_PATH)ui_test_window.hpp \
12.                    $(QTTMP_PATH)qrc_resource.hpp \
13.                    $(QTTMP_PATH)moc_window.hpp
14.  OBJ_FILES       = main.o
15.
16.  all: QtTest
17.  QtTest : $(QTCOMPILE_FILES) $(OBJ_FILES)
18.          g++ $(LIB_PATH) -o $@ $(OBJ_FILES) $(QTLIBS)
19.
20.  .cpp.o:
21.          g++ $(INC_PATH) -c $<
22.
23.  $(QTTMP_PATH)moc_%.hpp : %.hxx
24.          moc $< -o $@
25.
26.  $(QTTMP_PATH)qrc_%.hpp : %.qrc
27.          rcc $< -o $@
28.
29.  $(QTTMP_PATH)ui_%.hpp: %.ui
30.          uic $< -o $@
31.
32.  clean:
33.          rm $(QTTMP_PATH)*
34.          rm *.o $(TARGET)

Heresy 不確定這樣是不是最好的寫法,但是至少在 Heresy 這裡,都是可以用的;而也由於考慮到修改的方便性、擴充性,有不少東西都是定義成變數的形式。當然,也還有更多的東西也都可以變數化,這點就是視個人需要做調整了~

閱讀更多»

C++ 語法再加強:C++0x

目前一般所使用的 C++ 語法標準,實際上大部分應該都是俗稱 C++98 / C++03 的 ISO/IEC 14882:1998、ISO/IEC 14882:2003;其中 C++03 主要是針對 C++98 做部分修正,變化並不大(微軟 VC++ team 的 說法:C++03 只是 C++98 的「Service pack」)。那 C++ 有打算再有追加新功能嗎?實際上,目前也有還在規畫中、沒有正式定案的 C++0x 草案了!(詳細可以參考維基百科上的 C++ / C++0x 的條目)

而隨著新版 GCC(4.4/4.5)和 Visual Studio 2010 的推出,程式開發者也可以開始使用 C++0x 裡的部分新功能了!不過由於實際上 C++0x 是還沒正式定案的標準,所以其實不管是最新的 GCC 或 Visual C++ 2010,也都還沒有能完全支援 C++0x 的全部功能;實際上 C++0x 的規格也還在變動中,像 concepts 就被廢掉了。

Heresy 這一篇,主要會是以 Microsoft Visual C++ 2010 為主,介紹一些新的 C++0x 的語法;而 GCC 不同版本對 C++0x 的支援性,則建議可以參考官方的《C++0x Support in GCC》一文(用 g++ 編譯時需加上「-std=c++0x」這個參數)。

閱讀更多»

用 snprintf / asprintf 取代不安全的 sprintf

在 C 語言裡,要建立一個字元陣列的字串,常常會使用 sprintf() 這個函數來做格式化的處理。但是實際上,這個函式卻不是那麼「安全」。怎麼說呢?sprintf() 的整個介面長的樣子的是:

int sprintf ( char * str, const char * format, ... )

也就是在使用前,必須要先建立好一個字元陣列的空間,再用這個函式把內容填入,下面就是簡單的例子:

int tmp = 10;
char cstr[20];
sprintf( cstr, "%d * %d = %d", tmp, tmp, tmp * tmp );

在這個例子裡,cstr 最後的值,會是「10 * 10 = 100」,看起來好像很好?但是如果把 tmp 的值改成 10000 的話,cstr 則應該要變成「10000 * 10000 = 100000000」,但是由於這時候的字串所需長度為 26,而要寫入的 cstr 的長度只有 20,所以就會造成 buffer overflow 的問題。

閱讀更多»

一些電腦相關小東西的記錄

一些個人的記錄了…

  1. ImgBurn 和 Windows Media Player 相衝

    • 在 Windows Media Player 開啟時,使用 ImgBurn 的預設設定會沒辦法進行燒錄。這是由於 Media Player 也會去存取光碟,而這導致了 ImgBurn 沒有辦法鎖定光碟機、進入排他模式造成的。
    • 而實際上這問題是可以解決的!打開 ImgBurn 後,選取 [Tools] 的 [Settings],在 [Write] 這一頁裡 [Options] 中,有一項 [Lock Volume – Exclusive Access],只要把這項取消掉不要勾,就不會有這個問題了~

閱讀更多»

在 Linux 上實作 C++ 在 VC++ 的 getch()

這是前兩天,和網友討論的東西。主要命題就是:「要怎麼用 C++ 寫一個 console 的程式,可以取得單一按鍵的輸入?」也就是類似「按任一鍵繼續」的功能了~

Heresy 本來以為很簡單,後來才發現非常地麻煩… 首先,一般習慣在用的 scanf() 或是 cin,都必須要按下 Enter 後,才會開始處理;找了好一段時間的資料,也試了好久,才大概確定,他們應該都沒有辦法符合這個要求。

而在 Windows 上用 Visual C++ 的話,只要先 include conio.h 後,就可以直接使用 getch() 這個函式了~完整程式,也就只要下面這樣就夠了

閱讀更多»