コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2007年11月1日 >>> 2007年11月1日
link もっと後

2007年11月1日

もー!変なことするからこんがらがるんだよ!

GNU netcat 0.7.1(※)でポートのlistenはできるのに、別のホストにconnectしようすると無視されてしまいます。PCでコンパイルすると動くので、環境依存かなあ?と思ってprintfデバッグしていたら、複雑といえば複雑だけどしょうもない問題だったことに気づいてがっくり…。

以下はflagset.cの135行目あたりにあるint netcat_flag_count(void) という関数内の処理です。


char c;
int ret = 0;

while (c) {
  ret -= (c >> 7);
  c <<= 1;
}

この処理はcの中の1になっているビットを数える処理です。retには1だったビットの数が格納されます。例えばc = 3だったらret = 2です。

ぱっと見ret -= とマイナスするの部分が奇妙に見えます。理由としてはcの最上位ビットが1(つまりマイナスの値)ならば、c >> 7としたときに符号が維持されたままシフトされ、-1になるためです。もし最上位ビットが1でなければc >> 7は0になります。つまりc >> 7は -1 or 0になるので、ret -= で符号を反転させて足してあげています。
極めてわかりづらいです。なんでこんなことするんでしょうか。

それはさておき、このコードの何が問題かというと、char = signed charだと決めつけていることです。世の中にはchar = unsigned charとするコンパイラもあります。というか実際、そういうコンパイラが目の前にあります。しかし大抵の人がchar = signed charだと思っていることを踏まえると、char = unsigned charという設計は避けるべきだと思います。
このコンパイラを作った人は意地悪というか…ちょっとひねくれてたんでしょうね。

C言語ではcharがsigned charであるという決まりも、そもそも8ビットであるという決まりすらないので、こういうコードを書くと変な環境に持って行ったときにはまります。え、変な環境を作る方が悪い?ま、それも一理あります。

ちなみにunsiged charのときは、c >> 7の計算で符号拡張されませんので、c >> 7が -1 or 0になって欲しいはずが1 or 0になってしまい、retが減算されてしまいます。すると正負が逆になってしまって、結果netcatは引数がねーよ、と判断してしまうわけです。こんなことになるくらいならいっそsigned charなんて使わずにunsigned charを使った処理の方が感覚的にわかりやすいと思うのは私だけでしょうか?
GNUの中の人も変わってるわねえ。

まとめるとGNU netcatはchar = signed charと仮定した処理が入っていたので、char = unsigned charの環境に持って行くとおかしくなりますよ、って話でした。

それにしてもコンパイラ作者、GNUの中の人と、世の中にはひねくれ者が多いですなあ…。プログラムに限らず何事をやるにしても変な思いこみをしないように気をつけたいものです。

(※)FreeBSDやDebian GNU/Linuxは違うnetcatを使っているようです。GNU netcatを採用しているディストリビューションは少ないと思われます。

編集者:すずき(2007/11/02 19:21)

コメント一覧

  • hdkさん(2007/11/02 21:05)
    むかし使ってた LSI C-86 試食版も unsigned でしたね。SJIS を扱うには好都合でした。そのプログラムは... 自分でかくと &1 と >>=1 で書きそうだ。(当然 unsigned じゃないとおかしくなりますねw) x86 アセンブリで書くとキャリーフラグを使ってコンパクトにかけます。
  • すずきさん(2007/11/02 23:19)
    LSI C もかー。もしや DOS 時代って unsigned が普通?
    上記のプログラムですが、自分も書けと言われたら、素直に unsigned と、右シフト、(c & 1) で書きます。
    アセンブリかあ、x86 のことだから、一発でビット数える命令があってがっくり…なんてありそうですね。
  • hdkさん(2007/11/02 23:51)
    MS-C は違ったと思うけど... 忘れました。さすがに一発で数えるのはないですよね。8bit の 1 のビットが偶数個か奇数個かの判断ならパリティビットで一発ですが。普通に書けばこんな感じかなあ。
    xor eax,eax
    l1: shr cl,1
    jnc l2
    inc eax
    l2: jnz l1
  • すずきさん(2007/11/03 01:42)
    >ビット数える命令
    さすがの x86 にもないすか。
    >パリティ
    そういやそんなビットが flags の中にありましたねえ。ARM にもあるかなーと思ったけど、なかったです。
    x86 ってほとんど使わない機能が満載ですね…。
  • hdkさん(2007/11/04 14:01)
    縮めようとしたけど縮まらなかった... 32bit 版 (入力ecx,出力eax):
    sub eax,eax
    L1:
    stc
    adc ecx,ecx
    adc eax,0
    loop L1
  • すずきさん(2007/11/05 22:33)
    短くないけど、テスト対象の両端に近いビットだけが 1 だと速いコード。
    xor %%eax, %%eax
    bc_again:
    bsf %%ecx, %%edx
    jz bc_end
    btr %%edx, %%ecx
    adc $0, %%eax
    jmp bc_again
    bc_end:
    (入力 ecx, 出力 eax, 破壊 edx, 長さ 15byte)
  • すずきさん(2007/11/05 23:02)
    参考までに、hdk 氏の 1番目のは 9byte で、2番目のは 10byte でした。
open/close この記事にコメントする



link もっと前
2007年11月1日 >>> 2007年11月1日
link もっと後

管理用メニュー

link 記事を新規作成

<2007>
<<<11>>>
----123
45678910
11121314151617
18192021222324
252627282930-

最近のコメント5件

  • link 24年4月22日
    hdkさん (04/24 08:36)
    「うちのHHFZ4310は15年突破しまし...」
  • link 24年4月22日
    すずきさん (04/24 00:37)
    「ちゃんと数えてないですけど蛍光管が10年...」
  • link 24年4月22日
    hdkさん (04/23 20:52)
    「おお... うちのHHFZ4310より後...」
  • link 20年6月19日
    すずきさん (04/06 22:54)
    「ディレクトリを予め作成しておけば良いです...」
  • link 20年6月19日
    斎藤さん (04/06 16:25)
    「「Preferencesというメニューか...」

最近の記事3件

  • link 24年4月25日
    すずき (04/26 16:49)
    「[AVIFの変換] AVIFが読めないアプリケーションがたまにあるので、AVIF(AV1 Image File Format)...」
  • link 24年2月7日
    すずき (04/24 02:52)
    「[複数の音声ファイルのラウドネスを統一したい] PCやデジタル音楽プレーヤーで音楽を聞いていると、曲によって音量の大小が激しく...」
  • link 24年4月22日
    すずき (04/23 20:13)
    「[仕事部屋の照明が壊れた] いきなり仕事部屋のシーリングライトが消えました。蛍光管の寿命にしては去年(2022年10月19日の...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 04/26 16:49