Hatena::Grouphackathon

zrail (a.k.a. tobira17, h14i, ...) の Learning Log

2014-04-10

[]「C言語の関数引数の紛らわしいところ」を読んでメモ 06:57 「C言語の関数引数の紛らわしいところ」を読んでメモ - zrail (a.k.a. tobira17, h14i, ...) の Learning Log を含むブックマーク はてなブックマーク - 「C言語の関数引数の紛らわしいところ」を読んでメモ - zrail (a.k.a. tobira17, h14i, ...) の Learning Log

no title

上の記事。

構文糖って奴のおかげで分かりにくくなってる。

仮引数の配列はポインタとして扱われる、って話をネットでもよく見かけるけど、実際は最初の次元だけはポインタとして扱われるというのが正しいみたい。(参考:C言語の関数の仮引数における配列型宣言の危険性について - yuyarinの日記

一応コードとコンパイラの出力貼っとく。

#define MAX 10
void f1(int n[MAX])
{
}

void f2(int n[][MAX])
{
}
void f3(int (*n)[MAX])
{
}

int
main()
{
    int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int b[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    void (*g1)(int*);
    void (*g2)(int [][MAX]);
    void (*g3)(int (*)[MAX]);

    g1 = f1;
    g2 = f2;
    g3 = f3;

    g2 = f3;  // これでも警告でない
    g3 = f2;

    g1(a);:
    g1(b);
    g2(&a);
    g2(&b);
    g3(&a);
    g3(&b);

    return 0;
}

次はgccの吐いた警告。

 % gcc -Wall exp_array.c
exp_array.c: In function 'main':
exp_array.c:34:5: warning: passing argument 1 of 'g2' from incompatible pointer type [enabled by default]
     g2(&b);
     ^
exp_array.c:34:5: note: expected 'int (*)[10]' but argument is of type 'int (*)[11]'
exp_array.c:36:5: warning: passing argument 1 of 'g3' from incompatible pointer type [enabled by default]
     g3(&b);
     ^
exp_array.c:36:5: note: expected 'int (*)[10]' but argument is of type 'int (*)[11]'

まぁあんまり二次元以上の配列を直接扱うことはないんだけど…。

2011-09-06

[][]1ヶ月空いた 21:43 1ヶ月空いた - zrail (a.k.a. tobira17, h14i, ...) の Learning Log を含むブックマーク はてなブックマーク - 1ヶ月空いた - zrail (a.k.a. tobira17, h14i, ...) の Learning Log

いやー怠惰な一ヶ月だった。

写経くらいしかやってなかったな。酷い。


ところで、 C/C++単体テストって手軽にやる方法はないんだろうか。ここでのテストは TDD 的な意味での Developer Testing ね。

いや C++ は boost.test とか Cutter とかのおかげで結構簡単にやれるんだけど、 pure C の場合が分からない。

  • なるべく粒度の細かいテストを書きたい(理想を言えば 1 assert/test に近づけたい。)
  • テストランナーに登録するのは面倒(忘れる可能性もある)

ってときにどうすればいいのかなー。面倒くさがらずいっぱいテストドライバを書くのが王道なんだろうけどね。


邪道な解決方法もあるにはある。

標準規格では C の関数内で関数を定義することはできない。しかし、 gcc の拡張ではネストした定義ができる。それを使えば main ではテストランナーだけを実行して、テストケースはテストランナー内で定義する、という方法が使える。(っていうか main の中でテストケース書けばいいんじゃねっていう)

それから高階関数型言語 C を使う方法も testing に使えるんじゃないだろうか。

僕も tcc のソース読もう。斜め読みした感じでは噂ほど読みづらいわけではなかったし。

2011-02-06

[][]rake って便利だよね 06:23 rake って便利だよね - zrail (a.k.a. tobira17, h14i, ...) の Learning Log を含むブックマーク はてなブックマーク - rake って便利だよね - zrail (a.k.a. tobira17, h14i, ...) の Learning Log

去年まで「修行のため」などという中二病的な理由で頑張って Makefile を作っていたんだけど、さすがにアホらしくなってきて rake を使うようになった。

便利すぎて目からしょっぱい汁が……、みたいな感じになった。

相当時間を無駄にしてたなぁ。

omake とかも便利だけど、身の回りの環境では rake が一番ポータビリティが高い感じ。


メモ(というか何というか)

  • rake
    • 汎用のビルドツール
    • みんなが大好きな make とか Ant とかみたいな感じ
    • Rakefile を作ってルール(タスク)を記述
  • extconf.rb
    • Ruby の拡張ライブラリを作るための Makefile を生成するツール
    • Ruby の拡張ライブラリ専用の automake みたいな感じ
    • extconf.rb を作ってルールを記述

2011-01-23

[][]SWIG を使ってみる 05:40 SWIG を使ってみる - zrail (a.k.a. tobira17, h14i, ...) の Learning Log を含むブックマーク はてなブックマーク - SWIG を使ってみる - zrail (a.k.a. tobira17, h14i, ...) の Learning Log

C/C++単体テストC/C++ 自身で書くのが面倒だなーと思って SWIG を使う方法を調べた。ちなみに SWIG はテスト専用のツールじゃなくて、グルーって奴です。

基本的にはリンク先の記事とほぼ同じなので、そっちを参考にしたほうが良いです。

Simplified Wrapper and Interface Generator :本家

500 Internal Server Error

きまぐれ日記: もっと SWIG を!

Ruby Programing with SWIG

no title


以下、 Ruby と一緒に使う方法。他の言語でもだいたい一緒っぽい。

基本的な流れは

  1. C/C++ のヘッダ (*.h/) とライブラリ本体 (*.c や *.cpp) を書く
  2. SWIG のインターフェースファイル (*.i) を書く
  3. swig -ruby *.i とかする
  4. extconf.rb を書く
  5. make する
  6. Ruby から呼ぶ
/* sample.h */
void hello_to(char *str);
int add(int a, int b);
/* sample.c */
#include <stdio.h>
#include "sample.h"

void hello_to(char *str)
{
    printf("Hello, %s\n", str);
}

int add(int a, int b)
{
    return a + b;
}
/* sample.i */
%module sample
%{
#include <stdio.h>
#include "sample.h"
%}

void hello_to(char *str);
int add(int a, int b);
# extconf.rb
require 'mkmf'

$CFLAGS += " -Wall"
create_makefile("sample")
# call_sample.rb
require_relative 'sample'

Sample.hello_to('world')
puts Sample.add(1, 1)

っつーか、単体テストが面倒で~とか言いながら、サンプルがテストじゃないじゃん。あとで作り直そうかな。

*追記

キャストのことを考えると結構面倒だよね。

TDD で使うのも微妙かも。関数を追加するたびに .i を編集しなきゃならないし。

ヘッダファイルからインターフェースファイルを生成するように自動化すればいいだけか。

2010-12-04

[]tcc の -Wall は弱い 00:04 tcc の -Wall は弱い - zrail (a.k.a. tobira17, h14i, ...) の Learning Log を含むブックマーク はてなブックマーク - tcc の -Wall は弱い - zrail (a.k.a. tobira17, h14i, ...) の Learning Log

tcc の -Wall はあまり厳しくないようだ。

% gcc -Wall test_null_effect.c
test_null_effect.c: In function ‘main’:
test_null_effect.c:7: warning: statement with no effect
test_null_effect.c:8: warning: ‘a’ is used uninitialized in this function
% tcc -Wall test_null_effect.c
%

ちなみに test_null_effect.c の中身はこんな感じ。

#include <stdio.h>

int main()
{
    puts("Test Wall");
    int a;
    1 + 1;
    printf("%d\n", a);
    return 0;
}

まぁ別にそういう方向の品質を tcc に求める奴はいないだろうから問題ないんだろう。

どっちかっていうと man にも載ってるサンプルだけど、こういうのが楽しい。

echo 'main(){puts("hello");}' | tcc -run -

ちなみにファイル名が test_null_effect.c なのは、「C 実践プログラミング 第 3 版」(原題: "Practical C Programming" )に「こういうコードをコンパイルすると null effect 警告が出るだろうよ」的なことが書いてあったから試してみた。

実際は no effect だったんだけど。