パークのソフトウエア開発者ブログ|ICT技術(Java・Android・iPhone・C・Ruby)なら株式会社パークにお任せください -18ページ目

パークのソフトウエア開発者ブログ|ICT技術(Java・Android・iPhone・C・Ruby)なら株式会社パークにお任せください

開発の解決方法や新しい手法の情報を、パークのエンジニアが提供します。パークのエンジニアが必要な場合は、ぜひお気軽にお問い合わせ下さい。 株式会社パーク:http://www.pa-rk.co.jp/

下記のようなCのコードがあります。
#include <stdio.h>
#include <stdarg.h>

static long sum(int n, ...)
{
    long total = 0;
    va_list ap;
    va_start(ap, n);

    int i;
    for (i=0; i < n; i++)
    {
        total += va_arg(ap, long);
    }
    va_end(ap);
    return total;
}

int main(int argc, char *argv[])
{
    printf("a) %ld\n", sum(10, -1L, -2L, -3L, -4L, -5L, -6L, -7L, -8L, -9L, -10L));
    printf("b) %ld\n", sum(5, 1, 2, 3, 4, 5));
    printf("c) %ld\n", sum(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    return 0;
}

このコードを64bitのLinux上でビルドします。
 $ gcc -m64 -Wall -g -o sample sample.c
実行すると以下の結果が得られます
 $ ./sample
 a) -55
 b) 15
 c) -21474836425

c)の結果が55でないのはlong(64bit)の引数にint(32bit)と解釈される1..10を渡してるからでしょ?
ちゃんと 1L とか (long)1 とかすれば?と思いますよね。ご尤もその通りです。

でも b) はなんで正しい結果が得られてるのに c)はダメなの?というのが今回の本題。

調べたところ、関数の呼び出し規約 がx86_64の場合、

  • 整数・ポインタ引数 : RDI, RSI, RDX, RCX, R8, R9 の6個のレジスタ
  • 浮動小数点引数 : XMM0 ~ XMM7 の8個のレジスタ

が使用され、これ以上の引数はスタックに積まれて渡されます。


よって b) のケースでは 6個の引数なので全てレジスタ(64bit)に格納されてセーフ
c) のケースでは 6 ~ 10 がスタックに32bitずつしかコピーされずにアウトという理由でした。

objdumpで逆アセしてみると 6~10までが movlで32bitしかコピーされていないことが判ります。

  $ objdump -S sample
    :
  printf("c) %ld\n", sum(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
  4006fd:       c7 44 24 20 0a 00 00    movl   $0xa,0x20(%rsp)
  400704:       00
  400705:       c7 44 24 18 09 00 00    movl   $0x9,0x18(%rsp)
  40070c:       00
  40070d:       c7 44 24 10 08 00 00    movl   $0x8,0x10(%rsp)
  400714:       00
  400715:       c7 44 24 08 07 00 00    movl   $0x7,0x8(%rsp)
  40071c:       00
  40071d:       c7 04 24 06 00 00 00    movl   $0x6,(%rsp)
  400724:       41 b9 05 00 00 00       mov    $0x5,%r9d
  40072a:       41 b8 04 00 00 00       mov    $0x4,%r8d
  400730:       b9 03 00 00 00          mov    $0x3,%ecx
  400735:       ba 02 00 00 00          mov    $0x2,%edx
  40073a:       be 01 00 00 00          mov    $0x1,%esi
  40073f:       bf 0a 00 00 00          mov    $0xa,%edi
  400744:       b8 00 00 00 00          mov    $0x0,%eax
  400749:       e8 e2 fd ff ff          callq  400530 <sum>
    :

キチンとサフィックスLを付けると以下のようにmovqで64bitコピーされ正しい結果が得られます。
  printf("c) %ld\n", sum(10, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L));
  400760:       48 c7 44 24 20 0a 00    movq   $0xa,0x20(%rsp)
  400767:       00 00
  400769:       48 c7 44 24 18 09 00    movq   $0x9,0x18(%rsp)
  400770:       00 00
  400772:       48 c7 44 24 10 08 00    movq   $0x8,0x10(%rsp)
  400779:       00 00
  40077b:       48 c7 44 24 08 07 00    movq   $0x7,0x8(%rsp)
  400782:       00 00
  400784:       48 c7 04 24 06 00 00    movq   $0x6,(%rsp)
  40078b:       00
  40078c:       41 b9 05 00 00 00       mov    $0x5,%r9d
  400792:       41 b8 04 00 00 00       mov    $0x4,%r8d
  400798:       b9 03 00 00 00          mov    $0x3,%ecx
  40079d:       ba 02 00 00 00          mov    $0x2,%edx
  4007a2:       be 01 00 00 00          mov    $0x1,%esi
  4007a7:       bf 0a 00 00 00          mov    $0xa,%edi
  4007ac:       b8 00 00 00 00          mov    $0x0,%eax
  4007b1:       e8 7a fd ff ff          callq  400530 <sum>
    :
寧ろ、c) より b) が正しい結果を得られる事の方が恐ろしいですね。

(printfなど標準関数を除いて)可変引数は警告出ないので気を付けましょう。
そんなにたくさんの引数を使うことは希でしょうが・・・

先週 Rust 1.0.0 がリリースされましたね!
Haskell と C++ の間のような印象を持っていますが、私はまだ実際にコードを組んだことがありません。
これから少し勉強してみるつもりです。
((日本語リソースが増えてくるまで少し待とうかな...))

Rust はシステムプログラミング言語で、関数型(←明言はしていないらしい)、代数的データ型とパターンマッチングがあり、変数はデフォルトで不変、何より10億ドル相当の苦痛と損害がありません!
D 言語と同様、プログラマーがミスしやすいことはコンパイルエラーにしてくれそうです。
開発ツールが成熟してくれば非常に扱いやすく実用的な言語になると個人的には思っています。
((Haskell は素晴らしい言語だと思うのですが、ハードルの高さ的にちょっと... とか考えると、 Haskell 的な機能があって C っぽい文法を持つ Rust は実用的かも、という意味で。 Scala のことは後で考える。))
((中核概念の 1 つ『オーナーシップ』が広く受け入れられるには時間がかかる気も... C++ やってると受け入れやすいと思うけど C++ の人口って...))

参考

さて
プログラミング言語には使い手に敬意を表した呼び方がありますよね。
たとえば Python 使いを Pythonista, Ruby 使いを Rubyist と呼んだりします。
Go 言語を扱う人のことは Gopher と呼ぶらしいです。
((私は Gopher はゴメンです))
Scala の Scalman(スカルマン) もおもしろい。

では
Rust を扱う人は何と呼びましょう??
決めの問題かとは思いますが
やはり Rustafarian でしょうか。
あるいは Rusterizer でしょうか。

そんなくだらないことばかり気にしてしまうちかでした

ちなみに
Rust Samurai というと Rust 勉強会コミュニティの 1 つ (またはその主宰者) になります。
「JavaScript Ninjaがいるんだから、Rust Samuraiが居てもいいだろ。Mozilla的に」 というギャグから始まった企画。 とのこと。すばらしいネーミング!

5/25 追記

すみません、調査不足でした。
「Rust使いはRustaceanと呼ぶらしい。」とのこと。

元ネタ:

はじめに

こんにちは。バグ太郎です。

タイトルの通り、今回は興味本位で調べたForthについて記事にしてみたいと思います。
Forthの主な特徴は手続き型でスタック指向、コードの記述に後置記法を用いる点です。

特徴

後置記法

後置記法は逆ポーランド記法とも言います。
「1 + 2」という式(中置記法)を例とすると、後置記法では「1 2 +」と表現します。
後置記法は日本語の文法と似ている。と評されますが、
「1 2 +」を「1と2を足す」と読むことができる為です。
まあ、日本語と文法が似ていること自体はForthにおいて特に利点にはなりません。
日本において「1 + 2」という式でも普通に「1足す2」で通じますし。
日本語の文法そのままに日本語で記述できるMindというForthベースの言語もありますが、
Forthにおいて後置記法を採用しているのは「コンピュータで利用するのに適した形にしたかったから」と、単純に考えてよいかと思います。

スタック指向

Forthのデータ構造はスタックです。
後置記法と組み合わせることで明確なデータスタックを用いることができます。
「1 2 +」の場合、1を積み、2を積み、2値を取り出して、結果を積みます。
気をつけることといえば、pushとpopしたときのスタックポインタの移動する方向でしょうか。
スタックなので当たり前ですが「1 2」と積んだ場合「2 1」という順番で取り出します。

手続き型

Forthは複数の命令を組み合わせて、実行する一連のステップを記述します。
中置記法は演算子が数字の間に入るので「1+2」と書くことができますが、
後置記法は数字が続くために「12+」と空白を除いて書くことができません。
Forthにおいて各命令のデリミタには空白を用いるため、違和感なく「1 2 +」と同様の記述ができます。
実装してみると分かるのですが、適当なとこで改行しないと書いたコードを読み返したくはないです。
しかし命令ごとに改行すると過剰になって、無駄に縦に長くなります。

実行

Forthの環境はコンパイラとシェルが混ざったような感じです。
一時的に実行を試すための環境が欲しい方はWebサービスを探してみるとよいかもしれません。
Forthはコンパイルしなくても基本的な命令は対話形式でそのまま実行できます。
もちろんサブルーチン(Forthではwordsという)を定義し、それを対話形式で呼び出すこともできます。

「1 2 +」の結果を出力

# 1 2 + .


定義するときは以下のような形で記述します。

wordsの定義

: ワード名 文 ;


ためしにFizzbuzzなるものを実装してみました。
最初は思い描いた平凡なフロー通りに書いて無駄が多かったのですが、スタック指向を理解するにつれ変形させていくのが楽しかったです。
みなさんも試しに実行してみてはいかがでしょうか。私が使用した主なワードは以下の通りです。
ちなみに、繰り返しなどの一部制御文を使用する場合はコンパイルが必要になるようです。

・dup
 値をpopして複製してpushする。
・mod
 剰余算を行う
・if - then:if 文 [else 文 ]then
 分岐処理を行う。Forthにおいて0以外は真の扱いらしい。thenはendifでもよい。
・.(ピリオド)
 値をpopして出力する。文字列を出力する場合は." XXX"と記述する。
・cr
 改行を行う。
・do - loop: 終了値 開始値 do 文 loop
 100 1 do なら1から99までくり返す。iと記載すると現在値がpushされる


以下が私が実装したものになります。"最大値 fizzbuzz"と打ち込んで実行します。
0=を使用しているのはorは使えたのになぜかnorやnotが使用できなかったためです。

私が考えたForthのFizzbuzz

: fizzbuzz
cr
1 + 1 do
i 5 mod 0= i 3 mod 0= 2dup or 0=
if i . then if ." Fizz" then if ." Buzz" then
cr
loop
;

意味単位で成型すればこんな感じ?

: fizzbuzz
cr
1 + 1 do
i 5 mod 0=
i 3 mod 0=
2dup or 0=
if i . then
if ." Fizz" then
if ." Buzz" then
cr
loop
;



Forthを使う機会があるかは別として、普段触れない指向を学んでみるのも面白いのではないでしょうか。
皆様、お久しぶりです、紅焔です

去年5月に書いた前回記事とはまた別件でjspで外部のjarファイルを使用する時に少しトラブったのでご紹介しておきます

あるモジュール(jar)を組み込むため、WebContentのWEB-INF/libにそのjarを置きました。
ここまでは、バッチリ!
前回の反省を活かしてますね

このモジュールは、axis2等必要なjarファイルを同時に参照に含めないと使えない仕様です。
ライセンス上などの問題も考慮し、外出ししてあるのです。
これらのjarファイルをまとめたフォルダをWebContentのWEB-INF/libに置いて、ビルドパスを通す。
これで、動くはず…!

java.lang.NoClassDefFoundError

はい、出ましたー…。
ちゃんとWEB-INF/libに入っているはずなのに…。

答えはこうでした。
使用する全てのjarファイルはWEB-INF/libのフォルダそのものに入っていなければならない
子フォルダに置いていてもダメなんですねぇ…。

些細な事で躓く人が少なくなることを願い、締めとさせて頂きます。

はじめに

clangの静的解析機能をlinux上でも使ってみようという趣旨の記事です。

clangとは

clangはmacのxcodeでも使用されているC/C++/Objective-Cのコンパイラです。
コンパイラ基盤のLLVMのフロントエンドとして動作しオプションなどはgccと互換性があります。
gccと比較して最適化に長けていて、警告やエラーメッセージが判りやすいなどの特徴があります。

環境

CentOS 6.6 x86_64

インストール方法

EPELリポジトリの登録

CentOSには標準でclangのパッケージが用意されていないのでEPEL拡張パッケージのリポジトリを追加します。

# wget http://ftp.riken.jp/Linux/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
# rpm -ivh epel-release-6-8.noarch.rpm

clang-analyzerのインストール



# yum install clang-analyzer
(1/4): clang-3.4.2-4.el6.x86_64.rpm | 20 MB 00:19
(2/4): clang-analyzer-3.4.2-4.el6.noarch.rpm | 77 kB 00:00
(3/4): llvm-3.4.2-4.el6.x86_64.rpm | 1.2 MB 00:01
(4/4): llvm-libs-3.4.2-4.el6.x86_64.rpm | 7.8 MB 00:04

依存するLLVMとclangもインストールされます。

使い方

以下のような些末なコードがあったとして・・・

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int func(const char *str, char **dest)
{
*dest = strdup(str);
if (*dest == NULL) return -1;
char *pos = strstr(*dest, "foo");
if (pos != NULL) memcpy(pos, "bar", 3);
return 0;
}

int main(int argc, char **argv)
{
char* src = argv[1];
char* dest;
int ret = func(src, &dest);
printf("%s => %s\n", src, dest);
// free(dest);
return 0;
}


clangの--analyzeオプションで解析



$ clang --analyze zzz.c
zzz.c:19:5: warning: Value stored to 'ret' is never read
ret = func(src, &dest);
^ ~~~~~~~~~~~~~~~~
zzz.c:22:5: warning: Potential leak of memory pointed to by 'dest'
return 0;
^~~~~~~~
2 warnings generated.


scan-buildコマンドでHTMLレポートを作成



$ scan-build clang zzz.c
scan-build: Using '/usr/bin/clang' for static analysis
zzz.c:19:5: warning: Value stored to 'ret' is never read
ret = func(src, &dest);
^ ~~~~~~~~~~~~~~~~
zzz.c:22:5: warning: Potential leak of memory pointed to by 'dest'
return 0;
^~~~~~~~
2 warnings generated.
scan-build: 2 bugs found.
scan-build: Run 'scan-view /tmp/scan-build-2015-04-26-145938-25383-1' to examine bug reports.

$ scan-view /tmp/scan-build-2015-04-26-145938-25383-1
Starting scan-view at: http://127.0.0.1:8181
Use Ctrl-C to exit.


以下のようなHTMLレポートが作成されます。
scan-build


現実世界では単一のソースファイルに静的解析出来てもあまりうれしくないです・・・
以下はcmakeのプロジェクトに対して使用する場合です。

cmakeで使用する場合



$ cmake -DCMAKE_C_COMPILER=/usr/libexec/clang-analyzer/scan-build/ccc-analyzer -DCMAKE_CXX_COMPILE=/usr/libexec/clang-analyzer/scan-build/c++-analyzer /path/to/src
$ make


最終的なビルドはgccを使用する場合でも静的解析用途に使ってみてはいかがでしょうか?