ラベル C言語 の投稿を表示しています。 すべての投稿を表示
ラベル C言語 の投稿を表示しています。 すべての投稿を表示

2016年8月23日火曜日

風のごとくコンパイルする

風キッズの皆さんお久しぶりです。
今回は風のようにコンパイルする方法を紹介します。
基本的には以前の記事と同じ内容になりますが多少改良を加えてみました。
ここでは/usr/local/binにパスが通っているものとします。

$ sudo vi /usr/local/bin/compile

でコマンドを作成し、以下をコピペしてください。

#!/bin/sh
# Compile C file.
set -Cue

if [ $# == 0 ]
then
    echo "No argument."
    exit 1
fi

if [ -f $1.c ]
then
    gcc -o $1 $1.c -lm -lfftw3 -x c -g -Wall -Wextra ${@:2}
else
    echo "No such a C file."
    exit 1
fi

実行権限を与えます。
$ sudo chmod +x /usr/local/bin/compile

これでどこでもhoge.cを
$ compile hoge -option1 -option2
でコンパイルできます。

ある順番以降の任意の個数の引数を後ろにつける方法はこちらの記事を参考にしました。
また、gccの警告オプションについての説明はこちらの記事なんかがいいんじゃないかと思います。

2013年11月25日月曜日

clangでcomplex型使った時のwarningを消す



標準Cライブラリの複素数型を使う時,
complex c;
みたいな変数宣言を含んだファイルをclangでコンパイルするとすごくwarningが出る.

厳密には,
_Complex double c;
みたいに複素数の実虚の型まで含めて宣言してあげる必要があるらしい.

ただ,これだと型名が長くてめんどくさい.
今までどおり complex c; で定義したい,かつwarningも出したくない場合は,
#undef complex
typedef _Complex double complex;
のような文章を複素数型のincludeの後に入れてあげると良い.

2013年6月17日月曜日

引数が可変個のgccのコマンド簡略化

こちらの記事でも紹介されているように、よく使うコマンドは簡単なコマンドで置き換えてしまうと楽です。
でも僕の場合、頻繁にg++でコンパイルするのですがプログラムによって
g++ main.cpp -g -Wall -o main -lmylib
でコンパイルできることもあれば
g++ main.cpp -g -Wall -o main -lmylib -litpp -ljpeg -ltiff -lgsl
などと多数の外部ライブラリを用いることもあります。
ダイナミックライブラリなら全て後者でやっても問題無いのかもしれませんが、何か腑に落ちません。

なので可変個数の引数を取れるようにしたコンパイルコマンドの簡略化をシェルスクリプトで試みました。
以下がソースです。
# 引数1個めと2個めは入力ファイル、出力ファイル
function cc(){
    arg=("$@")
    command="gcc -O3 -g -Wall ${arg[1]} -o ${arg[2]} -lmylib"

    if [ $# -gt 2 ]; then
        for i in `seq 3 $#`
        do
            command="${command} ${arg[$i]}"
        done
    fi
    
    echo $command
    eval $command
}
ここでは-lmylibは必ず使うという前提でやってます。
あんま需要無いかもしれませんがよろしくです。

2013年2月2日土曜日

グローバル変数の危険性

プログラムで何でも便利だからといって何でもかんでもグローバル変数にするのはよくありません。




2012年12月20日木曜日

C言語ちょっと知識

プログラム高速化への道は難問であり、可読性との兼ね合いもあります。そこで、トリッキーですが、int型の初期化において排他的論理和を用いた手法を提案したいと思います。
int v;

v ^= v;//初期化
ちなみに、筆者の友人の環境によると、v=0とくらべて、2×10^(-8) [s]早くなりました。 時間がない人はお試しください。


2012年12月11日火曜日

配列のコピー

配列のコピーって、意外と面倒ですよね。僕の場合、for文を使って要素を一つづつ代入させてました。もっと簡単にできないかなと思って考えているうちに、構造体をつかえばいいんじゃないかなと思いました。

struct array_tag{int x[100]};

struct array_tag a,b;
a=b;


ではでは~。


2012年12月5日水曜日

丸め誤差の脅威( ゚ρ゚ )アゥー

みなさんはプログラムの数値がコンピュータ内では全て2進数として扱われていることはご存知ですよね!?
実はこの性質が引き起こすバグが存在し得ます。



2012年12月2日日曜日

FAQ C言語

C言語で疑問をもつとグーグル先生に相談する方も多いと思いますが、教科書的なものをみつけたのでこちらも参考にすると知識が深まりそうです。

FAQ


*ただし、ちょっと古いです。


2012年11月15日木曜日

風のごとく飛ぶ: etags

みなさんは、プログラムのソースコードを書いているときに
「あれ、この関数どうやって使うんだったっけな」とか
「途中まで関数の名前出てるけど最後まで思い出せない」とか思ったときありませんか?
そんなときすぐにその関数の詳細を見たいけど、「どのファイルで定義してあったかな」とか「確かあのファイルにあるけど開くのめんどくせー」とかっていうオチになるでしょう。
そんなとき、Emacsなら風のようにすぐにその関数の定義に飛ぶことが出来ます。
それにはetagsという機能を使います。



2012年11月14日水曜日

メモリリークを調べる

ぐるぐるまわるプログラムを書いてるとだんだんメモリ使用量が増えてくポップな現象いわゆるメモリリークが起きることがあるので調査可能なBoehm GCというライブラリを紹介します.

○ インスコ

Boehm GCのソースはここにあります.
./configure → make → make install のコンボでインストールできます.

○ 使う

4個くらいのナンセンスなプログラムを例にぐるメポップの見つけ方の例を示します.

(0) 準備
define GC_DEBUG
include "gc.h"
define malloc(n) GC_MALLOC(n)
define calloc(m,n) GC_MALLOC((m)*(n))
define free(p) GC_FREE(p)
define realloc(p,n) GC_REALLOC((p),(n))
define CHECK_LEAKS() GC_gcollect()
デバッグ用に上の文を書いときます.プログラム内でmallocした領域がBoehmの管理下に入ります. ちなみにこれを導入したプログラムをgccでコンパイルするときのオプション例は以下.
gcc -o TS TS.c -I/usr/local/include -L/usr/lib -lgc

(1) ループ内でmallocしたアドレスを何度も同じポインタ変数に代入しよう
int main(void)
{
  GC_find_leak = 1;
  
  int i; int *p;
  for(i=0;i<100;i++){
    p = (int *)malloc(100*sizeof(int));
  }

  exit(0);
  return 0;
}
GC_find_leak=1は ぐるポ検出モードです. return の前に exit してるのは return した瞬間にガベコレが働いていろいろうるさかったからです.Let Mr.Exit shut him upということです. とりあえずこれでちゃんと検出できました.やったね!v(^o^)v
実行結果はリークポイントが行数で表示されます.長いので端折りますが. ちなみにループが1回だと検出はしません.


(2) freeしないvoidのmalloc用関数を呼び出してみよう
void isalloc(int n)
{
  int *p;
  p = (int *)malloc(n*sizeof(int));
}

int main(void)
{
  GC_find_leak = 1;

  int i;
  for(i=0;i<100;i++){
    isalloc(100);
  }

  exit(0);
  return 0;
}
検出.これはループ呼び出し1回だけでも検出します.


(3) (2)のプログラムでちゃんとfreeしてみよう
void isalloc(int n)
{
  int *p;
  p = (int *)malloc(n*sizeof(int));
  free(p);
}
検出せず.

(4) (2)のプログラムで取得した領域をstaticなポインタ配列に代入して保持しよう
void isalloc(int n)
{
  int *p;
  static int num_hist=0;
  static int **p_hist;
  
  p = (int *)malloc(n*sizeof(int));
  p_hist = (int **)realloc(p_hist, sizeof(p_hist)+n*sizeof(int *));
  p_hist[num_hist++] = p;
}
これも検出せず.

ということで,領域のアドレスを保持したポインタ変数が生きてる場合は検出しませんが,解放してない領域のアドレスが手の届かないとこにいっちゃってfreeできない場合に有効みたいです.要するにこの書き方だと解放されずに上書きされたもののみ検出します.

役立つのか微妙ですが興味ある人はお役立てください.

2012年11月10日土曜日

対話式デバッガ: GDB

バグを取る、つまりデバッグの手段として一番シンプルな方法は恐らく文を出力することだと思います。
怪しい変数の値を出力させたり、途中でプログラムが止まってしまう場合は怪しい処理の前後で文を出力させたりなど。

それ以外にも、 この記事この記事の方法を使うという手もあります。

実はそれ以外にも方法があるんです!
それは、デバッガを使うということ。
gccやg++にはGDBというデバッグツールが提供されています。
その使い方を今回はご紹介致します。



2012年11月4日日曜日

複素乗算

複素乗算の演算量を減らす方法です。

 通常、実数乗算4回+加算2回ですが、実数乗算3回+加算5回にすることが可能です。 

一般的に、乗算は演算量が多いため、乗算回数はできるだけ減らすことが良しとされています。

complex MulComplex2(complex x, complex y)
{
  double temp;
  complex z;

  temp = y.im * (x.re - x.im);
  z.re = x.re * (y.re - y.im) + temp;
  z.im = x.im * (y.re + y.im) + temp;
  
  return z;
}




2012年10月29日月曜日

calloc & free

前回のプログラミング輪講で、領域確保の話が出てたので、ついでに使ってる関数の一部をのっけます。(これも、今年卒業した先輩からもらったものをいじっただけですが)

領域確保
int **imatrix(int row, int column)

{

  int i;

  int **x;

  

  x = (int**)calloc(row, sizeof(int*));

  for (i = 0;i < row;i++)

    x[i] = (int*)calloc(column,sizeof(int));



  //cheak

  if (x == NULL) {

    fprintf(stderr,"out of memory\n");

    exit(8);

  }



  return x;

}


領域解放
void i2dfree(int **p,int row,int column)

{

  int i;

 

  for (i = 0; i < row; i++)

    free(p[i]);

  free(p);

}


ここにあるのは、2次元int型用なので、double型・complex型も使いたい場合は、必要なところをint→double or complexに直して作ってください。

ちなみにmallocは領域確保のみですが、callocはmalloc後に初期化してくれます。



2012年10月23日火曜日

EmacsでC言語の編集に便利なコマンド

やあみなさん、風になってますか? 

Emacsをカスタマイズしまくるのもいいことですけど、デフォルトで使える機能でも便利なものはたくさんあります。
今回はプログラムを今まで以上に効率よく書けるようになる機能を紹介します。

まずauto-newlineモード。
これはC言語のソースコードを編集中に;(セミコロン)を打つと自動で改行してくれるモードです。 
やり方は
  • C-c C-a
もしくは
  • M-x c-toggle-auto-state
これで下のモードラインが(C)から(C/a)になれば成功です。

次はhungry-delete-keyモード。
これをオンにすると、カーソルの手前にある全ての空白をDelキーで削除することができます。
C-dでカーソルより後の空白も消せます。
やり方は
  • C-c C-d
もしくは
  • M-x c-toggle-hungry-mode
これで下のモードラインにhが出れば成功です。

上記2つのモードを同時に設定できるコマンドもあります。
やり方は
  • C-c C-t
もしくは
  • M-x c-toggle-auto-hungry-state

Cモードの起動と同時に自動でこれらをオンにしたい場合は、以下を.emacsファイルに書いておけばOK.
(add-hook 'c-mode-hook ;; c++-mode-hookの方がいいかも
'(lambda () 
(c-toggle-auto-hungry-state)))

 
        これで君も空気のような存在に近づけること請け合いだ!

2012年10月10日水曜日

C言語のプログラムにコマンドラインオプションを付ける

UNIX系のコマンドの後に-(ハイフン)と一緒に英語を付けたオプションをよく目にしますよね。
例えば
ls -a
とか
ln -s
とか
rm -d -f
など。

こういうオプションを自分で作れる方法があります。
オプションを付ける利点は、コンパイル時ではなく実行時にパラメータを変更できるというのもありますが、これから説明する方法を使うと引数の順番を気にしなくて良くなります。
さらにプログラムの使用方法なんかを表示させるオプションも付けられるので、久々に使うプログラムも困惑せずに使うことが出来ます。

ではやり方。
使うのはgetopt関数というもので、<getopt.h>をインクルードします。
僕もこの関数の仕様なんかはあまり分からず今のところテンプレに従って使っているだけなので、ここでは簡単な説明だけに留めておきます。
以下がテンプレ。
 
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>

static option options[] =
  {
    {"help", no_argument, NULL, 'h'},
    {"input", required_argument, NULL, 'i'},
    {"output", required_argument, NULL, 'o'},
    {"parameter", required_argument, NULL, 'p'},
    {"simple_version", no_argument, NULL, 's'},
    {0, 0, 0, 0}
  };

int main(int argc, char *argv[])
{
  char *input;
  char *output;
  int para;
  bool simple_ver = false;

  int c;
  int index;

  while((c = getopt_long(argc, argv, "hi:o:p:s", options, &index)) != -1){
    switch(c){
    case 'h':
      printf("Usage: This program is an example.\n");
      printf("       -i: Input file name.\n");
      printf("       -o: Output file name.\n");
      printf("       -p: Giving a parameter.\n");
      printf("       -s: Executing a simple program.\n");

      exit(0);

    case 'i':
      input = optarg;
      break;

    case 'o':
      output = optarg;
      break;

    case 'p': 
      para = atoi(optarg);
      break;
      
    case 's':
      simple_ver = true;
      break;

    default:
      std::cerr << "Error: An unknown option is appointed.\n";
      exit(1);
    }
  }

 ...
}

このソースがコンパイル通るかどうかは謎ですが、順に説明していきます。
まずmain関数外で定義されているoptions[]ですが、 これはoptionという型名の構造体の配列で、option型はgetopt.hにグローバル変数として定義してあります。
ここに使用したいオプションの名前を書いていきますが、メンバ変数の順番はまず最初にオプションの長い名前、次にそのオプションが引数を取るのかどうか(no_argumentrequired_argument)、3番目は必ずNULL、4番目にアルファベット1文字だけのオプション名を書きます。
そしてこの配列の最後は必ず{0, 0, 0, 0}の要素で埋めます。
これで-h, -i, -o, -p, -sというオプションが使えるようになります。

そしてmain関数内で具体的な挙動を定義します。
ここでは実際に使っているのはgetopt_longという関数です。
int型のc(charの方が良いのかも)にコマンドラインで指定された引数が格納されます。
getopt_long関数の引数には、main関数の引数であるargc, argv、そしてoptionsで作ったオプションを文字列として与えます。
:(コロン)の意味は、直前のオプションが引数を取ることを意味し、これがoptionsの引数(no_argumentrequired_argument)と間違っていると、コンパイルか実行時にエラーが出るはずです。
indexは多分何番目の引数なのかを格納するためだと思います。

そしてcに関するswitch文でオプションごとの挙動を定義していきます。
optargというのはgetopt.h内で定義されたグローバル変数で、 各オプションの引数が格納されます。
たとえば、
./program -i inputFile.dat -o outputFile.dat -p 3 -s

のように実行したとします。
すると、iのオプションのときはoptarg="inputFile.dat"となり、oのオプションのときはoptarg="outputFile"といった具合になります。
./program -h

でhelp文を表示できます。

getopt関数とは違い、getopt_long関数はoptionsで指定した長い名前の形式でもオプションを指定できます。
つまり
./program --help

これで-hのオプションを指定したのと同じ挙動になります。

わーわー言うとりますけども、お時間です。
かなり分かりづらい説明なので、質問、訂正なんかがあればコメントください。

2012年6月22日金曜日

Fork関数



ぜひ、やってみよう。

#include<unistd.h>

int main(){

while(1){

fork();
}


}


_


2012年6月7日木曜日

Segmentation fault の原因

コンパイルは通ったのに,いざ実行してみたら"Segmentation fault"の表示.
誰でも一度は通る道だと思います.

慣れてくると,どうやってバグを取り除けばいいかわかってくるかと思いますが,
その原因となることを幾つか紹介していきます.

1,確保していない領域を使おうとしている

これが,ほぼすべての"Segmentation fault"の原因であると思います.
こんなことを書いちゃうと発生します.

int array[10];
array[15] = 20;

これは明らかに確保していない領域を使おうとしていますよね.
こんな場合だとすぐに見つけられると思いますが,たくさんの配列を使用していて,
forループで内容をいじっている場合などは問題に気づきにくい場合があります.
また,そのforループ自体では"Segmentation fault"が発生せず,不正利用している
アドレスに他のデータが重ならないとエラーが出ない場合があります.
例えば,N=50の時にはエラーが出なかったのに,N=5000にしたら"Segmentation fault"
が発生する.といった具合です.
そうなってしまったら,gdbコマンドや"printf()"を駆使して,
どこでエラーが発生するのか頑張って探しましょう.
基本的には"Segmentation fault"が発生している部分の"前"で
間違いを犯しているはずです.


2,2次元配列などでかなり大きな領域を確保しようとする

こちらは"Segmentation fault"が発生する位置が,問題を起こしている部分より"前"
にくる可能性があって,気をつけなければならないエラーとなります.
エラー自体は単純なもので,二次配列(またはそれ以上)の形で,
大変大きな領域を確保しようとした場合に発生します.

int matrix[3000][2000];

こんな具合で大きな領域を確保しようとした場合に,"Segmentation fault"が
発生します.
この解決法は単純で,配列の領域確保を"動的配列(malloc, calloc)"
で確保してやれば大丈夫です.

int **matrix;
int row = 3000, column = 2000, i;

matrix = (int **)malloc(sizeof (int*) * row);
for(i = 0; i < row; i++){
   matrix[i] = (int *)malloc(sizeof (int) * column);
}

これで解決するのですが,"Segmentation fault"が発生する部分より後ろ,
具体的には,関数内において,

void func(...){
printf("check\n");

int matrix[3000][2000];
...
}

と書いた場合に,"check"が表示されずに"Segmentation fault"が発生してしまいます.
これは,1.で示したように"前"の部分を探しても発見できず,発見が遅れるバグです.
気をつけてください.









2012年4月12日木曜日

FFTW


通信分野において出番の多い離散フーリエ変換。ディジタル処理ではそれを高速に計算するアルゴリズム(高速フーリエ変換, FFT)が使われ、みなさんもシミュレーションに組み込む機会があるかと思います。
1度自分で作りその仕組を理解することは非常に重要なので最初から使うことは勧めませんが、その後研究を進めていく上で計算速度やバグ取りの効率など考えると配布されているものを使ってもいいと思います。


・FFTは「FFTW」というものが配布されていますので、これからその導入の仕方を追っていきましょう。


【セットアップ】
1.まず、FFTWをパソコンにインストールする必要があります。私が導入した時点では「fftw-3.2.2」くらいのヴァージョンです。google先生に「FFTW」「mac」とか入れれば教えてくれるでしょう。


2.インストールが完了したら、ターミナルでホームフォルダから/usr/local/includeの場所に「fftw3.f」「fftw3.h」があるか確認しましょう。ホームフォルダから
ls /usr/local/include
とコマンドすれば見れます。確認できたら、前準備はおしまいです。




ここからは使い方を具体的なソースコードを例にしながら確認していきます。
実際あんまよくわかってないんですがわかっている事を書いていくので、参考程度に。

#include <complex.h>
#include <fftw3.h>
#define FFTSIZE 4
// Complex型を使うと便利です。fftw3.hをインクルードします。
// FFTSIZEはNとかなんでもいいです。FFTの大きさです。

int main(void)
{
int i;
complex *in, *out1, *out2;
fftw_plan p1,p2;
// fftw_complexという型はcomplexと思っておkです。
// fftw_planというのは見慣れないのですが、これにどういうFFTを行うのかの入れます。

in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * FFTSIZE);
out1 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * FFTSIZE);
out2 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * FFTSIZE);
// complex型の配列を準備してるだけです。

in[0] = 1 + 1*I;
in[1] = 1 + 1*I;
in[2] = 0 ;
in[3] = 0 ;
// 適当に数値を設定しました。好きなように変えてください。

p1 = fftw_plan_dft_1d(FFTSIZE,in,out1,FFTW_FORWARD,FFTW_ESTIMATE);
p2 = fftw_plan_dft_1d(FFTSIZE,out1,out2,FFTW_BACKWARD,FFTW_ESTIMATE);
// 第一引数にFFTの大きさ、第二引数に入力、第三引数に出力、
// 第四引数はFFTなのかIFFTなのかどうか、第五引数は要調査。

fftw_execute(p1);
 // これがFFTを実行する関数
fftw_execute(p2);
for(i=0;i<FFTSIZE;i++){
out2[i] /= FFTSIZE;
}
 // FFTWは1/Nしてくれないので自分で正規化しましょう
  // 通信の場合はFFTとIFFTの両側で1/sqrt(N)とかですね。
  // sqrtを使う場合はmath.hのインクルードを忘れずに。


fftw_destroy_plan(p1);
fftw_destroy_plan(p2);
// planを破棄、まーいちお書きましょう。

for(i=0;i<FFTSIZE;i++){
printf("%f %f\n",creal(out1[i]),cimag(out1[i]));
}
putchar('\n');
for(i=0;i<FFTSIZE;i++){
printf("%f %f\n",creal(out2[i]),cimag(out2[i]));
}
// 結果表示

fftw_free(in); fftw_free(out1); fftw_free(out2);
return 0;
}

それでは、また(^o^)ノ

2012年4月2日月曜日

プログラミングへの第一歩

ここでは研究室に入りたてのメンバー向けにプログラムの作り方を紹介します。

まずは作業用フォルダを作りましょう。
自分のホームフォルダ直下に置いた方がやりやすいです。
あと名前は英語で。
ここでは"programming"とでもしておきます。

次にソースコードを書きます。
研究室のメンバーなら最初はEmacsを使って書くことになります。
Emacsを開いたら次のコマンドを入力します。
C-x C-f

C-っていうのはCtrlボタンを押しながらってことです。
そしたらEmacsの下の細長いウィンドウにファイル名を入力します。
Find file: ~/programming/hello.c
ファイル名は例です。
入れたらEnterで決定。
すると"programming"フォルダに"hello.c"というファイルが出来ます。

ここからソースコードを書きます。
とりあえずは例として以下のようなソースコードを書いたことにします。
#include <stdio.h>

int main(void){

    printf("Hello, World!¥n");

    return 0;

}
これを以下のように保存。
C-x C-s

このコマンドはこまめにやっておいたほうがいいです。

そしたら次はiTermを起動します。
以下のように入力。
~> cd programming
programming> gcc hello.c -o hello
これで"programming"フォルダに"hello"という実行ファイルが作成されます。
実行するにはiTermで以下のように入力。
programming> ./hello
これで例の文章が出力されれば成功です。

以上のような方法で簡単なプログラムが作れるようになります。
あとはEmacsのコマンドを覚えたり、ソースファイルが多くなってきたら分割コンパイルなどを駆使して効率よくプログラミングをしましょう。