new之後,constructor之前

昨天在代碼裡面看到一個從沒看過的用法,如下列紅色標示部份:

#include <iostream>

class MyBase {
  protected:
    int _id;

  public:
    MyBase():_id(0) {}
    MyBase( int id ):_id(id) {}
    int getId() {return _id; }
};

class MyClass: public MyBase {
  public:
    MyClass() {}
    MyClass( int id ):MyBase( id ) {}
};

int myclass_mem[ sizeof(MyClass)/sizeof(int) ];

using namespace std;

MyBase* test()
{
  return new (myclass_mem)MyClass( 100 );// 這裡 (1)
  //return new MyClass( 100 ); // (2)
}

int
main( int argc, char* argv[] )
{
  int len = sizeof( myclass_mem );
  cout << "The size of myclass_mem is " << len << endl;
  cout << "content of myclass_mem" << endl;
  for( int i=0; i<len; i++ )
    cout << myclass_mem[i] << ” “;
  cout << endl;

  MyBase* base = ::test();
  cout << base->getId() << endl;

  cout << "content of myclass_mem" << endl;
  for( int i=0; i<len; i++ )
    cout << myclass_mem[i] << ” “;
  cout << endl;
}

以執行的結果來說,我實在是分辨不出來 (1) 與 (2) 有甚麼分別。
後來我用 gcc -S 去分別產生組合語言碼,總算是大致猜到了,原來以 (1) 的方法來寫,會把 new 以後的結果也複製到 myclass_mem 這個陣列裡面。
所以加上輸出 myclass_mem 內容的程式碼,再分別產生執行檔來看執行結果就很清楚了。
真是特別。

Duff’s Device

國二菜鳥忙裡偷閒看到這篇Duff’s Device.
這段 code, 真的很神奇

register n = (count + 7) / 8; /* count > 0 assumed */
switch (count % 8)
{
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (–n > 0);
}

不過我必須承認,在看了它提供的參考網址以後,我不知道這段 code 在幹麼….
參考網址:

longjmp/setjmp

這是一組有趣的 api, 一般性的用法,是先使用 setjmp 設定 break point, 之後要跳回來的時候,就使用 longjmp.
所以,用法大概是這樣…

#include <stdio.h>
#include <setjmp.h>
jmp_buf setjmp_buffer;
int
main( int argc, char* argv[] )
{
if( setjmp( setjmp_buffer ) == 0 )
{
// do something
printf(“longjmp!!\n”);
longjmp( setjmp_buffer, 1 ); // 用 0 的話, setjmp() 就會收到 0, 那麼可能會無窮回圈
}
else
{
// do something
printf(“after longjmp.\n”);
}
}

很簡單吧,應該也可以兜出 try … catch … finally 的用法.
下面是我大致的想法

int exception_id;
if( ( exception_id = setjmp( setjmp_buffer ) ) == 0 ) // try
{
// do something
longjmp( setjmp_buffer, 1 ); // throw
}
else
{
if( exception_id == 1 ) // catch( 1 )
{
}
if( exception_id == 2 ) // catch( 2 )
{
}
// ….
}
// 之後,就是 finally…

之後再參考書看看吧… ^^

用 wprintf 輸出 string

wprintf() 要印一個 wchar 字串時,得特別使用 %ls,如果你用 %s, 那表示要印一個一般的 char 字串。
所以這樣會只印出 m

wchar_t* myString=L”music is wonderful!!”;
wprintf( L”%s\n”, myString );

而這樣才會正確的印出 “music is wonderful!”

wchar_t* myString=L”music is wonderful!!”;
wprintf( L”%ls\n”, myString );

printf

神奇的用法….老實說….我以前的確不知道可以這樣用~~
三人行必有我師
#include <stdio.h>
int main()
{
int i;
i=23;
printf(“%*s\n”, i, “blah”);
printf(“%*s\n”, i+1, “blah”);
}
這樣就可以自由決定格式了….
我以前大概會先用字串去串出前面的格式字串吧~~

ltdl library

可以輸入 info libtool 找 Module loaders for libltdl 就可以得到不少資訊.
簡單說,就是可以製作能動態載入 module/plugin 的 library, 以 linux 來說,底層其實就是 dlopen, dlsym 這些函數
這個 library 其實是一個 wrapper, 跨了好幾個平台: BSD, Linux, Win32…
configure.in 中的設定
AC_LIBLTDL_CONVENIENCE
AC_SUBST(LTLINCL)
AC_SUBST(LIBLTDL)
AC_LIBTOOL_DLOPEN
AC_PROG_LIBTOOL
AC_CONFIG_SUBDIRS(libltdl)
Makefile.am 中的設定
SUBDIRS=libltdl
INCLUDES=$(LTDLINCL)
prog_LDFLAGS=-export-dynamic
prog_LDADD=$(LIBLTDL) “_dlopen” self “_dlopen” fxx.la
prog_DEPENDENCIES=$(LIBLTDL) fool.la
prog 指的是執行檔名稱
而 module/plugin 的 Makefile.am 設定
xxx_la_LDFLAGS=-module
函數蠻多的,可以直接從 ltdl.h 去找或參考 info
對於 Multi-Thread 也有支援.

Linux Timezone programming HOW-TO

以前在作 NAS (Network Attached Server) 的時候,因為要取得並設定時區,所以去找到的資料.
主要是參考這篇 The GNU C Library – Time Zone Functions.還有一些其他 Linux 程式的方式來解決.
不過 GNU C 的這個 timezone functions 似乎不太 work,我想可能是我不會用吧~~後來是改用 symbolic link 的方式來解決~~
以下用問答的方式來記述:
1.如何取得目前 timezone?

在設計上,可以將 /etc/localtime symbolic link 到 /usr/share/zoneinfo 下的 zone file. 藉著取得真實路徑的函數readlink(),就可以得知是哪裡的 timezone.

2.如何設定 timezone?

同 1, 可以用 symbolic link 的方式來設定

3.和 TZ Environment Variable 的關係

如果有設定 TZ 環境變數,那麼 /etc/localtime 將會失效.
TZ 有特定格式,需要查一下,大多的 embedded system 都是直接利用 TZ 環境變數,而不使用 zone file.

4.如何瀏覽 zone??

可以直接開啟 /usr/share/zoneinfo/zone.tab 來取得列表.
此檔共有四欄: code, coordinates, TZ, comments.
照慣例,以 # 開始的該列為註解.
比較需要用到的兩個欄位: TZ 與 comments.

5.預設值??

預設值可以直接指向 /usr/share/zoneinfo/GreenWich 表示為格林威治標準時間

向侯捷請問STL sort的問題

這是蠻久以前的事情了,那時候為了這個 sort 的問題,發 mail 向侯捷先生請教.雖然隔了很久才回覆我,不過心裡還是很感動~~也才知道自己的程式出了什麼錯.

回覆日期:2003年2月20日 上午 03:38
你的程式寫的邏輯不對。
> bool operator==( const myInt& l, const myInt& r) {
> bool operator>( const myInt& l, const myInt& r) {
> bool operator<( const myInt& l, const myInt& r) {
這三個都沒有完整判斷。sort 的時候,要求 class 需定義 operator<,
而 operator< 在什麼時候應該傳回 0, 什麼時候傳回 正值,什麼時候傳回負值,有一定的規則。
問題不是出在你指的地方,而在這裡。
— jjhou
—– Original Message —–
寄件者: "晏仁"
收件者:
傳送日期: 2002年10月8日 PM 11:07
主旨: 請教 STL sort() 的問題
> Dear 侯sir:
>
> 冒昧請教,以下是程式,而問題在最後面~
>
> #include <iostream>
> #include <algorithm>
> #include <vector>
>
> using namespace std;
>
> class myInt {
> protected:
>   int id;
> public:
>   myInt():id(0) {};
>   explicit myInt( int i ):id(i) {};
>   myInt( const myInt& i ):id(i.id) { };
>   int getId( void ) const {
>     return id;
>   }
>   myInt& operator=( myInt& i) {
>     id=i.id;
>     return *this;
>   }
>   myInt& operator=( int i ) {
>     id=i;
>     return *this;
>   }
>   myInt& operator*() { return *this; }
>   myInt* operator->() { return this; }
>   friend bool operator==( const myInt& l, const myInt& r );
>   friend bool operator   friend bool operator>( const myInt& l, const myInt& r );
> };
>
> bool operator==( const myInt& l, const myInt& r) {
>   if( l.getId() == r.getId() )
>     return true;
> }
>
> bool operator>( const myInt& l, const myInt& r) {
>   if( l.getId() > r.getId() )
>     return true;
> }
> bool operator   if( l.getId()     return true;
> }
>
> class myIntCompare {
> public:
>   int operator()( myInt aa, myInt bb ) {
>     if( aa.getId() > bb.getId() )
>       return 1;
>     if( aa.getId() == bb.getId() )
>       return 0;
>     if( aa.getId()       return -1;
>   }
> };
>
> int
> main( int argc, char* argv[] ) {
>   const int COUNTS=10000;
>   typedef vector intVector_t;
>   intVector_t intVector;
>   int i;
>
>   /**
>    * 下面的兩行 code 會導致 segmentation fault,這就是我要問的問題!!
>    * for( i=COUNTS;i>=0;–i )
>    * intVector.push_back( myInt(i) );
>    */
>   intVector.reserve( COUNTS );
>   for( i=COUNTS; i>=0; –i )
>     intVector[i]=i;
>
>   // 以下兩種寫法都可以
>   sort( intVector.begin(), intVector.end(), myIntCompare() );
>   //sort( intVector.begin(), intVector.end() );
>
>   for( i=0; i     cout << intVector[i].getId() < }
>
> 為什麼把
>   intVector.reserve( COUNTS );
>   for( i=COUNTS; i>=0; –i )
>     intVector[i]=i;
>
> 改成
>   for( i=COUNTS;i>=0;–i )
>     intVector.push_back( myInt(i) );
>
> 編譯後再執行
> 就會發生 segmentation fault 的問題呢??
> 真的是很奇怪
> 我知道 vector 在配置的時候會先預留一塊記憶體
> 在 push_back() 的時候,如果發現不夠大,會自動重新配置,
> 並把原來的內容搬到新的地方去.
> 我想可能是重新配置的問題~~
> 但卻不知道真正的原因是什麼?
> 希望侯 sir 能給我一些方向,讓我下手去找出答案~
>
> 喔,對了,我的環境是 linux g++ 2.96.
>
> With Best Regards.

gcc 的超強 Warning 選項

想不到
真是想不到
gcc 的 Warning 選項居然可以做到可以檢查你的 code 是不是用了 char, 還有 enumeration 內定義的所有數字是否都被用了
功能真是超強~
但是今天下午被這個玩意兒卡了快一個多小時
真是可惡~~

C++ ABI

ABI 是 Application Binary Interface, 它是一種介於使用者 C++ 程式碼和提供實作系統和 library 的物件程式碼.
這包含了 C++ 資料物件的記憶體配置,包含先行定義和使用者定義的資料型態,也包含了內部 Compiler 產生的物件,如: virtual tables.
它也包含了函數呼叫介面,例外處理介面,全域名稱空間和多樣物件程式碼的協定.
GCC 將在 3.2 版以後為編譯器提供此功能~