宣言

まぁ、普通は typedef 使え、ってな話だよね。signal の宣言なんか typedef 使わないとひどい。

/* with typedef */
typedef void (*sighandler_t)(int);
signalder_t signal(int signo, sighandler_t handler);

/* without typedef */
void (*signal(int signo, void (*handler)(int)))(int);

ちなみに、宣言文と英語を相互変換してくれる Web サイトとかあったりする(ただし、仮引数の名前は書けない)。

変換プログラム自体も公開されている。

% wget http://cdecl.org/files/cdecl-blocks-2.5.tar.gz
% tar zxf cdecl-blocks-2.5.tar.gz
% make
yacc cdgram.y && mv y.tab.c cdgram.c
lex cdlex.l && mv lex.yy.c cdlex.c
gcc -g -O2 -o c++decl cdecl.c 
rm -f cdecl
ln -s c++decl cdecl
% ./cdecl
Type `help' or `?' for help
cdecl> explain void (*signal(int, void (*)(int)))(int)
declare signal as function (int, pointer to function (int) returning void) returning pointer to function (int) returning void
cdecl> exit

あと、C++ だとメンバへのポインタもあるのでさらにややこしいとか、const/volatile もあるよ、とかいう話も。

% ./c++decl
Type `help' or `?' for help
c++decl> explain int X::*x
declare x as pointer to member of class X int
c++decl> explain int (X::*x)(int)
declare x as pointer to member of class X function (int) returning int
c++decl> explain const int *p
declare p as pointer to const int
c++decl> explain int * const p
declare p as const pointer to int
c++decl> exit

追記1

sighandler_t の宣言を間違えていたので修正。

shared object 中のグローバル変数を出力する

shared object 中のグローバル変数の中身をそれなりの見た目にして出力するツールなど。まぁ、なんか shinh さんの dumper が元ネタなわけですが。

DWARF を読んで、型情報を読んでいるので、-g とか -gdwarf-2 とかつけてコンパイルする必要あり。あと、libelf と libdwarf が必要。Debian 系だと libelf-dev, libdwarf-dev かな。RedHat 系はよくわからんですが。

久しぶりに C++ などで書いて思ったこと。

  • メソッドのパラメータを変更すると宣言と実装の両方編集する必要あってめんどい。
  • Google では例外禁止とか聞いた気がしたので例外なしでやってみたら一々返り値のチェックが必要でめんどい。
  • そもそもエラー処理がめんどい。めんどいので assert でお茶を濁す

やりたいこととか

  • *.o の読み込み。なんかちゃんと libelf つかえばいけそう

できてないこと

  • 関数ポインタ
  • 列挙型。まぁ、普通にやれば出来そう。

そもそもこんなの欲しい人いるのかという話なんだが。

ぐぐる

反応が遅いですが。

shinh さんの発表に出てきた 「edit distance」をぐぐってみたら odz さんのはてダが結構上位で引っかかりました。

うぉ、ぐぐるとほんとに上位だ。

何かを調べてて、結構 odz さんのはてダがひっかかったりすることがあるので 最近こういった方面の書き込みがほとんどないのは残念だったり。

まぁ、なんというか昨年はいろいろ本業のほうがアレな状態なためにインプットがなくて必然的にアウトプットも減るという。まぁ、最近は結構改善されてきているんで、単にサボっているだけともいう。

カラー表示

ふと思った疑問。Emacs カラー表示っていつぐらいからできるようになったんでしょ? キーワードの色つけ表示が入った頃? 最初に実装したエディターは?

そいや、昔、VineEmacs には、color-mate なんてのが入っていたな、と思って color-mate 7.10 のパッケージの中身を見てみた。

ウィンドウシステムにあまり対応していない バージョン 1 の mule
バージョン 18 の emacs にも対応していて、できる限りカラー化します。その時
には、 mule / emacs が ウィンドウシステムに対応している必要があります。
カラーにならない時はこれが原因と考えられます。

なるべく バージョン 2 の mule や バージョン 19 の emacs を使用して下さい。
そのほうがより派手にカラー化できます。

とりあえず、emacs 18 ではカラー表示ができたようだ。

FTP

なんか、FFFTP の開発終了とのことらしいですが。
そもそも、FTP 自体がさっさと滅びて、WebDAV なり SFTP なりに置き換わるべきだと思う。といっても、SSH1 も Telnet も滅びる気配はないし、PGP だって普及する気配がないしな。実際にはまだまだしばらくは現役なんでしょうなぁ。

ローマ数字変換

えーと、じゃ、Scala で。
assert はテストとは違う気がするが、まぁいいか。

object RomanNumber {
  val romanDigits = List(
    ("M",  1000), ("CM",  900), ("D",   500),
    ("CD",  400), ("C",   100), ("XC",   90),
    ("L",    50), ("XL",   40), ("X",    10),
    ("IX",    9), ("V",     5), ("IV",    4),
    ("I",     1)
  )

  def parse(s: String): Int = {
    def parseImpl(s: String, digits: List[(String, Int)], result: Int) : Int =
      if (s.length == 0) 
        result
      else if (digits.isEmpty)
        throw new IllegalArgumentException()
      else if (s.startsWith(digits.head._1))
        parseImpl(s.substring(digits.head._1.length), digits, result + digits.head._2)
      else
        parseImpl(s, digits.tail, result)
    parseImpl(s.toUpperCase, romanDigits, 0)
  }

  def format(n: Int): String = {
    if (n < 1 || n > 3999)
      throw new IllegalArgumentException()

    def formatImpl(n: Int, digits: List[(String, Int)]): List[String] =
      if (n == 0)
        List()
      else if (n >= digits.head._2)
        digits.head._1 :: formatImpl(n - digits.head._2, digits)
      else
        formatImpl(n, digits.tail)
    
    def join(xs: List[Object]) = {
      val builder = new StringBuilder()
      for (x <- xs) {
        builder.append(x)
      }
      builder.toString()
    }

    join(formatImpl(n, romanDigits))
  }

  def main(args: Array[String]) {
    assert(format(11) == "XI")
    assert(parse("MDCCCLXXXVIII") == 1888)
    assert(parse("mdccclxxxviii") == 1888)
    assert(parse("McmXLv") == 1945)

    try {
      format(0)
      assert(false)
    }
    catch {
      case _: Throwable => Unit
    }

    try {
      parse("A")
      assert(false)
    }
    catch {
      case _: Throwable => Unit
    }
  }
}