frog.raindrop.jp.knowledge > C プログラミング
Cに関してです。Cはあんまり得意じゃないので、初歩的な話題が中心です。

March 4, 2009

IPv4 でマルチキャストに送出するパケットの TTL を設定する。

IPv4 でマルチキャストのパケットを送出する際、デフォルトのままでは TTL が 1 になってしまう。ルータ越えの必要がある場合は以下のようにして、送信に使用するソケットのオプションを変更する。(下記は TTL を 32 に変更した例)

// #include <Winsock2.h>
int ttl = 32;
int result = setsockopt (socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof ttl);
if (SOCKET_ERROR == result)
{
    // エラー処理は省略...
}

C# の場合はこんなの。

// using System.Net.Sockets;
int ttl = 32;
socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, ttl);

October 29, 2004

文字列の前後のホワイトスペースを取り除く関数

いわゆる TRIM 関数です。

//------------------------------------------------------------------------
//   trim						(文字列からホワイトスペースを取り除く)    
//------------------------------------------------------------------------
//  戻り値	: 先頭ポインタ
//------------------------------------------------------------------------
char *trim(
	char	*lpszString )	// (in)	処理対象の文字列
{
	char	*ps;	// 空白文字を除いた先頭
	char	*pe;	// 空白文字を除いた最後尾
	char	*p;		// ワークポインタ




	// 先頭を見つける
	for ( ps = lpszString; *ps; ps++ ) {
		if ( ( 0x81 == *ps ) && ( 0x40 == *( ps + 1 ) ) ) {	// 全角スペース
			ps++;
		}
		else if  ( 0x20 < *ps ) {		// ホワイトスペース以外→先頭
			break;
		}
		}

	// 最後を見つける
	for ( p = pe = ps; *p; p++ ) {
		if ( ( 0x81 == *p ) && ( 0x40 == *( p + 1 ) ) ) {	// 全角スペース
			p++;
		}
		else if  ( 0x20 < *p ) {		// ホワイトスペース以外→最後尾?
			pe = p;
		}
	}

	// コピー
	for ( p = lpszString; ps <= pe; ) {
		*p++ = *ps++; 
	}
	
	*p = '\0';
	return lpszString;
}

August 11, 2004

debug_printf

2chのどっかで拾ったコード。なるほどーと思ったので貼ってみる。

#ifdef	_DEBUG
#define	debug_printf	printf
#else	// _DEBUG
#define	debug_printf	1? (void)0: printf
#endif	// _DEBUG

July 15, 2004

VBからコールするダンプログDLL

続きを読む...

April 28, 2004

atoin 関数

atoi 関数のレングス指定あり版です。なんてことはないですが、しょっちゅう作るのも面倒かと思って。

続きを読む...

April 1, 2004

伝統形式 の 関数宣言

今日、こんな古いソースの中にこんな関数定義を見かけました。

int func (foo, bar)
unsigned char *foo, *bar;
{
    /* 処理・・・ */
    ・・・

注目すべきは引数の宣言部分なのですが、調べてみると「伝統形式」と呼ばれるものらしいです。

ANSI C標準以前の宣言方法を伝統形式や旧方式というように呼ばれています
この方式による宣言は現代のコンパイラでも可能です
さらに、過去のC言語のソースで伝統形式が使われているものを見かけることがあるかもしれません
ここで、伝統形式の仮引数宣言を覚えておきましょう
(中略)
大きく違うのは、引数リストで仮引数となる変数名しか宣言しないということです
その後、コードブロックに入る前にそれぞれの仮引数に型を宣言するという形になっています

March 24, 2004

error C2143

switch文の閉じカッコの位置で"error C2143: 構文エラー : ';' が '}' の前に必要です。"とコンパイルエラーになることがある。それはたとえばこんな場合。

switch ( foo )
{
case 'A':
	// 処理...
	break;
case 'B':
}

実はこれは、case 'B':ラベルと}の間に有効なステートメントが存在しないと起こるエラーである。回避策としては、break;でも書いとくか、なんなら;(セミコロン)だけの行でもよい。

March 11, 2004

DLL作成のためのDEFファイル

VBからコール可能なDLLの作成 ででてきた、DLL作成のための標準的なDEFファイル

LIBRARY [library][BASE=address]
EXPORTS
	entryname1[=internalname1] [@ordinal1[NONAME]] [DATA] [PRIVATE]
	entryname2[=internalname2] [@ordinal2[NONAME]] [DATA] [PRIVATE]
	entryname3[=internalname3] [@ordinal3[NONAME]] [DATA] [PRIVATE]
library
DLL の内部名を指定します
address
OSが DLL ファイルをロードするベース アドレス。指定なしは、0x10000000。
entryname
エクスポートする関数の定義名
internalname
エクスポートする関数内部名。省略時は同名の関数。
ordinal
エクスポートするエントリにつける番号。
NONAME
多分システムの隠し関数みたいに、名前はないけど@ordinalで呼び出せる関数になるんだと思う。未確認
DATA
??
PRIVATE
??

EXPORTS 文[MSDN ライブラリ Visual Studio 6.0]のところに載ってるけど、エントリの内容についてはあまり載ってないです。

March 10, 2004

ワークスペースをダブルクリックしたときに新たにVC++を起動する

以前から思っていたことだが、VC++で1つワークスペースを開いてて、別のDSWファイルををダブルクリックして開くと、先に開いてたのと同じVC++のウインドウで開いてしまい、最初に開いてたワークスペースは結果として閉じてしまう。複数VC++起動したのになーって。複数のワークスペースを開くには?に回答を発見した。

エクスプローラのメニューから [ツール]-[フォルダオプション] でプロジェクトワークスペースの設定をDDEを使用しないように変更すればOKです。

Windows Xpの場合はフォルダオプションの「ファイルの種類」で、拡張子DSWを選択し、「詳細設定」ボタンを押下、出てきたウインドウの「MSDEVで開く」をダブルクリックして、「DDEを使う」のチェックをはずせば期待の動作をするようになった。

March 9, 2004

VBからコール可能なDLLの作成

以前に、VC++でDLLを作る方法を調べたが、どうやらその方法で作成したDLLは、VBでDeclareを使用してコールすることができないらしい。
週刊Bravo!! > Programing Tips > Visual C++ > DLLの情報をもとに、私が理解した範囲では、

  • 関数はWINAPIで修飾する必要がある(__stdcall呼出規約である必要がある)
  • __stdcall関数は、__declspec(dllexport)でエクスポートすると、名前が_funcname@nのように修飾されてしまう(呼び出しは可能)
  • エクスポートはDEFファイルで行うと、関数名が修飾されない

というかんじ。

March 5, 2004

Cの宣言の読み方

Cの宣言はよみにくい。MSDNのヘルプを見ても???だったのでちょっと整理してみました。基本的な読み方は以下の順です。

  1. 識別子を探す
  2. 識別子の含まれる一番内側の丸カッコから、順に外側のかっこに向かって、以下を繰り返す。
    1. 識別子の後ろの()または[]を探す
    2. 識別子の前の*を探す

char *( *(*var)() )[10];を例にとると

  1. 識別子→var
  2. 識別子はポインタ
  3. 識別子は関数ポインタ
  4. 識別子のさす関数の戻り値はポインタ
  5. 識別子のさす関数の戻り値の要素10個の配列へのポインタ
  6. 識別子のさす関数の戻り値のさす配列の要素はポインタ
  7. 識別子のさす関数の戻り値のさす配列の要素はchar型のポインタ

February 25, 2004

VC++でDLLを作る

VC++でDLLを作るときのポイントです。

続きを読む...

February 24, 2004

文字・文字列あれこれ

文字定数と文字列リテラルの大きな違いとして、シングルクオートで括ったら\0が付かない、ダブルクオートなら付く、ってことらしい。Perlとは違うのね。
参考:プログラミング演習III ~C言語中級編~

関数あれこれ
strchr 文字列から文字を探す
strstr 文字列から文字列を探す
strrchr 文字列の中に文字が含まれている最後の場所を探す
_snprintf 引数にsprintfする
sscanf 文字列よりscanfみたいにして値を取り出す。

February 23, 2004

実数型の内部表現

実数型の内部表現で一般に用いられる形式、IEEE754 floating-point standard について。

先頭より、以下のようにビットを割り当てる。

S(符号部)
先頭の1ビット。正のとき0、負のとき1。
E(指数部)
単精度の場合は8ビット、倍精度なら11ビット
M(仮数部)
単精度なら23ビット、倍精度は52ビット
±1.M * 2E-127
0.375f = 1.5 * 2-2
- ---+---- 1----+----2----+----3--
0 01111101 00000000000000000000101
S└  E  ┘ └──── M ────┘

あと、指数部と仮数部の特別な組み合わせが存在する。

指数部(S) 仮数部(M)
±0 全部0 0
±Infinity 全部1 0
NaN 全部1 0以外

IEEE754 倍精度浮動小数点数のフォーマットに詳しく解説したものがあります。

rand, srand

Cの標準関数のsrand, randはPerlの同名の関数と動きが違う。つまり、min_val~max_valの乱数を求める場合はこんな感じ?(間違ってたら言ってください。)

srand( (unsigned)time( NULL ) );
n = min_val + ( ( max_val - min_val ) * ( (double)rand() / (double)RAND_MAX ) );

でも、max_val - min_valがRAND_MAXより小さいなら、これもありかも。

srand( (unsigned)time( NULL ) );
n = rand() % ( max_val - min_val ) + min_val;

August 24, 2003

C言語の switch は整数型?

VC++のヘルプで「C の switch ステートメント」(HTMLヘルプへのリンクです)をひいてみると、「switch expressioncase constant-expression には整数型を指定する必要があります。」と記述がある。C++は文字も指定できたような・・・という気がして、C++の方も見てみたが、「整数で」って書いてあるな・・・サンプルも文字はあっても文字列はない。
法大奥山研究室:C言語:14.4. switch文
で見ても定数に限るってあるし、整数らしい。VBから入った人間にはえ?って感じ。