Home > C言語 Archive

C言語 Archive

すぐ忘れるC言語用語

ビットフィールド。概念とか書き方とかは覚えてるんだけど名前が覚えられない。まあ、使わないからな。


struct hoge {
    unsigned b1: 1;
    unsigned b2: 1;
    unsigned b3: 6;
} fuga;

fuga.b1、fuga.b2は1ビットの変数、fuga.b3は6ビットの変数となってfugaは全体で1バイト。
とめもっておいて、ここで使ったことにしておく。そしたらきっと覚えられる。

以上

CSTLを使ってDLLを小さくするっていう話

小さいDLLを作るには下記サイトが参考になる。
http://www.geocities.co.jp/egggarden/win32api/miniexe.htm
ひとつのポイントとして
#pragma comment(linker, "/entry:\"DllMain\"")
を定義しておけばいいと言うのがあるんだが、これをやるといろいろな制限がつく。
この中でも私がはまった(なかなか気づかなかった)のが
 ・strcpyとかsprintfとかが使えない
 ・浮動小数点が使えない
 ・STLが使えない
だった。上記に違反すると、VCでリリースモードでビルドしようとしても、LNK2019エラーとやらで”error LNK2019: 未解決の外部シンボル _main が関数 ___tmainCRTStartup で参照されました。LIBCMT.lib”ってでてリンクできない。

strcpyとかはlstrcpyとかそういうWin32APIによる代替手段を使う。以下のサイトが参考になる。
http://www.arcpit.co.jp/winapi/api_01/ap010407.htm
浮動小数点に関しては、
EXTERN_C int _fltused = 0x9875;
をどっかに定義しとく。これが何かは全く謎だが、それで動くんだから仕方がない。
で、ここまではいいとしてもSTLはどうしようもない。もう自分で作るしかないのか!?と思われたときにCSTLを見つけたっていう。要するにSTLの代わりにCSTLを使っておけばLNK2019エラーを回避できるという話。
すごく便利です。

以上

C言語でSTL的なことができるCSTLがすごい&例えばDLLを小さくする

CSTL:http://cstl.sourceforge.jp/
これはすごい。
C言語で、ヘッダだけで、STLに近いことが、STLに近い形で使える、ライブラリ。
vectorやmapが普通に使える。
C言語なのになんでヘッダだけで使えるかというと、全部マクロで書かれているから。
機能を使いたい.cファイルでマクロを展開することで関数の実体を作るから、ヘッダをインクルードして一行マクロを書くだけでmapが使える。例えば下のような使い方。


#indlude <stdio.h>
#include "cstl/map.h"

// std::map<int, int>っていう型(=IntIntMap)を定義する。IntIntMapは任意の文字列でいい。
CSTL_MAP_INTERFACE(IntIntMap, int, int)
CSTL_MAP_IMPLEMENT(IntIntMap, int, int, CSTL_LESS)

// std::map<const *char, int>っていう型(=StrStrMap)を定義する。StrStrMapは任意の文字列でいい。
CSTL_MAP_INTERFACE(StrStrMap, const char*, char *)
CSTL_MAP_IMPLEMENT(StrStrMap, const char*, char *, strcmp)

int main(int argc, char *argv[]) {
   IntIntMap *iimap;
   StrStrMap*ssmap;
   char *fuga = "fuga";
   
   iimap = IntIntMap_new();   // 作成
   IntIntMap_insert(iimap, 1, 2);   // 挿入
   if (IntIntMap_find(iimap, 1) != IntIntMap_end(iimap)) {   // 検索
      printf("%d\n", *IntIntMap_lookup(iimap, 1));  // 参照
   }
   IntIntMap_delete(iimap);   // 解放

   ssmap = StrStrMap_new();   // 作成
   StrStrMap_insert(ssmap, "hoge", fuga);   // 挿入
   if (StrStrMap_find(ssmap, "hoge") != StrStrMap_end(ssmap)) {   // 検索
      printf("%s\n", *StrStrMap_lookup(ssmap, "hoge"));   // 参照
   }
   StrStrMap_delete(ssmap);   // 解放

   return 0;
}

begin()とかnext()とかも使えるし、multimapもある。
mapだけでなくstringまであるし、algorithmも一部用意されている。
これはすごい。ライセンスも修正BSDライセンスで使いやすい。

というわけで、例えば私の場合はdllのファイルサイズを小さくするためにこれを使ってみた。
という話は次のエントリにつづく。

以上

goto文が怖い

異常ケースのみgoto文を使ってエラー処理を行うっていう規約になってるんだが、エラー処理なんていっぱいあるのでgoto文を使いまくっているうちに、気がついたら「正常」にfalseを返す場合にもgoto文を使っていた。おそろしい。気をつけよう。

以上

Javaとかスクリプト言語からC言語に戻ってくると警戒しすぎて不思議に思ってしまうこと


typedef struct COPY_STRUCT {
   int a;
   char b[4];
   int c;
} COPY_STRUCT;

int main(int argc, char* argv[]) {
   COPY_STRUCT hoge, fuga;
   hoge.a = 1;
   memcpy(hoge.b, "abc", 4*sizeof(char));
   hoge.c = 2;

   fuga = hoge;
   memcpy(hoge.b, "def", 4*sizeof(char));
   printf("%d, %s, %d\n", fuga.a, fuga.b, fuga.c);
   return 0;
}

ちゃんと


1, abc, 2

って表示されるんだぜ?
COPY_STRUCT.bがポインタだったらだめだろうけど、サイズの決まった配列なら一気にちゃんとコピーしてくれる。当たり前のことだが、Cって配列とかはめんどくさいイメージがあるから、JavaとかPHPとかそういう高級な言語から戻ってくると警戒しすぎて不思議に思ってしまう。

以上

VC2008のバッファオーバーラン?

なぜかエラーにならない。


void overrun(void) {
	int i = -3;
	int test[100];

	test[i] = 1;
}


int _tmain(int argc, _TCHAR* argv[])
{
	overrun();

	return 0;
}

2003くらいだとエラーになる。/GSオプション入れとけばエラーが出ることもあるけど、どこでエラーなのか分からない。大丈夫か2008!

以上

最大スタックを調べる

自分のプログラムがどれくらいスタックを使っているのか。なかなか見積もりにくい。もう実測するしかねえ!と思いつつ、C言語でどうしたらいいのか。プロファイラーとか使えばできるのかもしれないけど、持ってないし。というわけで、簡単にやるには次のような関数を作っとく。


unsigned int minsp = 0xffffffff;
unsigned int max_stack(void)
{
    unsigned int sp;
    sp = (unsigned int)&sp;
    minsp = min(sp, minsp);
    return minsp;
}

で、どれくらいスタックを使っているのか知りたい場所でこれを呼ぶようにする。一番呼び出し階層が深そうなところとか。そうすると、max_stack関数内の自動変数spのアドレスが変わる。関数が呼ばれたときのスタックのトップ(あたり)にspが積まれるので、呼び出される度に最小のスタック位置を覚えておく。下記のように使う。


unsigned int minsp = 0xffffffff;
unsigned int max_stack(void)
{
    unsigned int sp;
    sp = (unsigned int)&sp;
    minsp = min(sp, minsp);
    return minsp;
}

void hoge(int a) {
   max_statck();
}

int main(int argc, char *argv[]) {
   unsigned int start;
   unsinged int end;
   minsp = 0xffffffff;
   start = max_stack();
   hoge();    // スタックを計りたい処理
   end = max_stack();
   printf("%d\n", (int)(start - end);
   return 0;
}

まあ、厳密じゃない気がするけど、目安にはなるんじゃないかな。

以上

Cでポインタを引数に渡すときに勘違いするなよ

下のようなのはバグに近いと思うんです。


void hoge (char *text) {
     if (text == NULL) return;
     free(text);
     text = NULL;
}

いや、別にちゃんと動くし、間違ってないし、そういう意味ではバグではないんですが。最後の「text = NULL」というのが意味がない。こう書いてしまう人は結構いるんじゃないかと思うんです。(自分も含めて)
上記では冒頭でNULLチェックをしているし、最後にNULLを代入するので連続で呼ばれても2重解放はしないぜ!って感があふれています。でも連続で呼ばれたら2重解放になります。なぜなら呼び出し元のtextはNULLにできないから。


void hoge (char *text) {
     if (text == NULL) return;
     free(text);
     text = NULL;
}

int main() {
   char *text = NULL;
   text = (char *)malloc(10);
   hoge(text);
   if (text != NULL) {
       printf("いやん\n");
   }
   return 0;
}

「いやん」となるわけです。hogeに渡されるのはtextのコピーなので、hogeの中で値を変えても無意味なわけだけども、textの指している先のデータをhogeの中で書き換えることはできるので勘違いしやすいんじゃないかなと。
あるいは下記のようなことはできません。


void fuga(char *text) {
   text = (char *)malloc(10);
}

いや、やってもいいけど期待したとおりには動きません。上のようなことをやりたい場合は


void fugaShinuchi(char **text) {
   (*text) = (char *)malloc(10);
}

int main() {
   char *text = NULL;
   fugaShinuchi(&text);
   free(text);
   return 0;
}

初心忘るべからずということで。

以上

マクロの引数の文字列

コマンドプロンプトでCppUnitとかってfail時にどのテストが失敗したのかが表示されるけど、どうやってやってるのかとちょっとみてみたら、引数に#をつけてた。ほう。


#define TEST(x) {printf("%s\n",#x);}

int main(int argc, char *argv[]) {
   int hoge = 1;

   TEST(hoge == 1);
   return 0;
} 

「hoge == 1」ってでる。超トリビアルだぜ!

構造体の初期化

テイルズ オブ ヴェスペリアの体験版をダウンロード中。

C言語の構造体を初期化します。書記化します。


typedef struct Hoge {
   int a;
   int b;
   char *c;
} Hoge;

int main(int argc, char* argv[]) {
   Hoge hoge = {0, 0, NULL};

   printf("%d, %d, %s", hoge.a, hoge.b, hoge.c);

   return 0;
}

こんな感じです。{}が初期化子です。メンバの値を列挙すればよいです。が、これは省略できます。


int main(int argc, char* argv[]) {
   Hoge hoge = {0};

   printf("%d, %d, %s", hoge.a, hoge.b, hoge.c);

   return 0;
}

省略すると、数が足りないメンバは0で初期化されます。
トリビアルメモです。

以上

Home > C言語 Archive

Search
Feeds
Meta
 合計:034780
 今日:0064 昨日:0482

Return to page top