time

time_t time( time_t *timeptr )

西暦1970年1月1日から何秒経ったかを秒数で返す。


#include <stdio.h>
#include <time.h>

void main()
{
 printf( "%ld\n", time( NULL ) );
}


・調べた秒数は戻り値で取得すればよい。
・引数には変数のアドレスではなくNULLを指定する。
・このデータはctime関数を使って読める形にする。
C > 標準関数 > 時間処理 | comments (0) | trackbacks (0)

符号あり右シフト

符号あり整数の右シフト動作は一定していません。
まず正の数の右シフトは左から0がシフトインされます。
負の数の場合は、ANSI Cでは規定していません。
処理系に依存するという事になっています。
その動作には2種類あります。


(1)符号ビットのコピーをシフトインする(算術シフト)
(2)0をシフトインする(論理シフト)


算術シフトは、算術計算に耐えるシフトを意味しています。
例えば-1000を右1ビットシフトしたら-500になるべきだというシフトです。
これに対して論理シフトは、
とにかく指定数だけシフトすればいいというシフトです。
負の数を右にシフトして、結果が正の数になっても構わないというものです。

このように右シフトには2つの方法がありますが、
実際には算術シフトをとっている処理系が大部分です。
それはシフト演算と算術演算とに一貫性がでてくるからです。
このようにシフト演算には処理系依存という要素がありますから
実際の運用にあたっては、
シフト処理は符号無し整数に対して行う
という姿勢が望ましいと言えます。
C > 演算 | comments (0) | trackbacks (0)

シフト演算


#include <stdio.h>
void main()
{
 int b = 1;
 printf( "%d %d\n", b * 2, b << 1 );
 printf( "%d %d\n", b * 4, b << 2 );
 printf( "%d %d\n", b * 8, b << 3 );
 printf( "%d %d\n", b * 16, b << 4 );

 int a = 16;
 printf( "%d %d\n", a / 2, a >> 1 );
 printf( "%d %d\n", a / 4, a >> 2 );
 printf( "%d %d\n", a / 8, a >> 3 );
 printf( "%d %d\n", a / 16, a >> 4 );
}


実行結果

2 2
4 4
8 8
16 16

8 8
4 4
2 2
1 1


シフト対象整数が正の時、
i * 2n と i << n は同じ結果になる。
i / 2n と i >> n は同じ結果になる。

左に1ビットシフトするごとに値は2倍になる
右に1ビットシフトするごとに値は1/2倍になる
C > 演算 | comments (0) | trackbacks (0)

WM_L(R)BUTTONDOWNメッセージ


LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
 HDC hdc;
 char str[256];

 switch ( message ) {
 case WM_LBUTTONDOWN:
  wsprintf( str, "左クリックされた" );
  hdc = GetDC( hWnd ); // デバイスコンテキスト生成
  TextOut( hdc, 1, 1, str, lstrlen( str ) );
  ReleaseDC( hWnd, hdc ); // デバイスコンテキスト解放
  break;
 case WM_RBUTTONDOWN:
  wsprintf( str, "右クリックされた" );
  hdc = GetDC( hWnd ); // デバイスコンテキスト生成
  TextOut( hdc, 1, 1, str, lstrlen( str ) );
  ReleaseDC( hWnd, hdc ); // デバイスコンテキスト解放
  break;
 }
 return 0;
}

Windows > ウィンドウプロシージャ | comments (0) | trackbacks (0)

WM_MOUSEMOVEメッセージ


LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
 HDC hdc;
 int xPos;
 int yPos;
 char str[256];

 switch ( message ) {
 case WM_MOUSEMOVE:
  xPos = ( int )LOWORD( lParam );
  yPos = ( int )HIWORD( lParam );
  wsprintf( str, "x=%03d y=%03d", xPos, yPos );
  hdc = GetDC( hWnd ); // デバイスコンテキスト生成
  TextOut( hdc, 1, 1, str, lstrlen( str ) );
  ReleaseDC( hWnd, hdc ); // デバイスコンテキスト解放
  break;
 }
 return 0;
}

Windows > ウィンドウプロシージャ | comments (0) | trackbacks (0)

WM_KEYDOWNメッセージ


LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
 HDC hdc; // デバイスコンテキストのハンドル
 static char str[128] = "";
 static int position = 0;

 switch ( message ) {
 case WM_KEYDOWN:
  str[ position++ ] = ( char )wParam;
  hdc = GetDC( hWnd ); // デバイスコンテキスト生成
  TextOut( hdc, 1, 1, str, position );
  ReleaseDC( hWnd, hdc ); // デバイスコンテキスト解放
  break;
 }
 return 0;
}



LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
 PAINTSTRUCT ps;
 HDC hdc;
 static int xPos = 1;
 static int yPos = 1;
 static int delta = 10; // 増減幅
 LPCSTR target = "+";

 switch ( message ) {
 case WM_KEYDOWN:
  switch ( wParam ) {
  case VK_RIGHT:
   xPos += delta;
   InvalidateRect( hWnd, NULL, 1 );
   break;
  case VK_LEFT:
   xPos -= delta;
   InvalidateRect( hWnd, NULL, 1 );
   break;
  case VK_UP:
   yPos -= delta;
   InvalidateRect( hWnd, NULL, 1 );
   break;
  case VK_DOWN:
   yPos += delta;
   InvalidateRect( hWnd, NULL, 1 );
   break;
  }
  break;
 case WM_PAINT: // メイン ウィンドウの描画
  hdc = BeginPaint( hWnd, &ps );
  // TODO: 描画コードをここに追加してください...
  TextOut( hdc, xPos, yPos, target, lstrlen( target ) );
  EndPaint( hWnd, &ps );
  break;
 }
 return 0;
}


InvalidateRectでウインドウのクライアント領域を破棄する命令を
Windowsに対して出します。
WindowsはWM_PAINTメッセージを発行するので、結果として描画できます。
Windows > ウィンドウプロシージャ | comments (0) | trackbacks (0)

WM_PAINTメッセージ


LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
 PAINTSTRUCT ps;
 HDC hdc;
 char str[] = "test";

 switch ( message ) {
 case WM_PAINT: // メイン ウィンドウの描画
  hdc = BeginPaint( hWnd, &ps );
  // TODO: 描画コードをここに追加してください...
  TextOut( hdc, 1, 1, str, ( int )strlen( str ) );
  EndPaint( hWnd, &ps );
  break;
 }
 return 0;
}


このメッセージは、自分の作成したウインドウが再描画された場合に
使用するメッセージで、プログラマが「ウインドウ画面が再描画されたら〜したい」
という場合にこのメッセージを使用する事になります。

<主にウインドウが再描画される場合>
・ウインドウのサイズを変更した場合
・最初にウインドウが作成されWM_CREATEが検出された後
・自分の作成したウインドウがアクディブ・ウインドウに切り替わった場合
Windows > ウィンドウプロシージャ | comments (0) | trackbacks (0)

プレフィックス

BOOLb-,f-
HANDLEh-
LPSTRlpsz-
DWORDdw-
WORDw-
UINTu-
BYTEn-,cb-
intn-
shortn-
charcb-,sz-
ポインタlp-
C > 基礎 | comments (0) | trackbacks (0)

算術変換と整数の昇格

算術変換
2項演算子に異なる型のオペランドを指定した場合、「精度の高い」ほうに型を揃えてから演算が行われる。
制度の高い順に
long double>double>float>unsigned long>long>unsigned int>int
となる。
※longとunsigned intの場合はunsigned longになる。

整数の昇格
int型よりもサイズの小さい整数は、演算の前に無条件に符号付int型に変換される。

原則

・ビットフラグなど、ビット単位の情報が重要なものは
符号無し整数にする。
・配列の要素数が多いなど、サイズが重要な場合には
できるだけ小さいデータ型にする。
・さもなければint


何かの個数や人の年齢といった値は負になる事が無い為、符号無し整数にしたくなるかも知れません。
しかし、こうした変数はintにしておく事で、余計な型変換を防ぐ事ができます。
また、charやshortを使用すると、整数の昇格によって余計な変換が発生する分だけ遅くなります。
C > 演算 | comments (0) | trackbacks (0)

and演算での剰余演算


#include <stdio.h>
void main()
{
 int i;
 for ( i=0; i<16; i++ ) printf( "%d ", i % 2 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i & 1 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i % 4 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i & 3 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i % 8 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i & 7 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i % 16 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i & 15 );
 printf( "\n" );
}


実行結果

0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15


i % (n2) は i & (n2-1) と同じである。
C > 演算 | comments (0) | trackbacks (0)

関数の記憶クラス

・関数に指定できるクラスはstaticとexternのいずれかである。
・static記憶クラスを持つ関数は、その関数が定義されているファイル内の関数からのみ呼び出す事ができる。
 他のファイルの関数からstatic関数を呼び出すことはできない。
・extern記憶クラスを持つ関数は、他のファイルの関数から呼び出す事ができる。
 関数の記憶クラスを省略した場合はexternが暗黙的に採用される。
・特定のファイル内の、特定の処理に特化した独立性の低い関数の場合は、名前の競合を避ける為にstatic記憶クラスを指定する事が推奨される。
C > 関数 | comments (0) | trackbacks (0)

typedef

構文
typedef 既存の型名 新しい型名


typedef struct { int x, int u } Point;


・構造体の宣言でタグ名は省略できるため、
 必要でなければ無名構造体に別名を与えた方が効率的である。
・構造体に別名を与えておくと、structキーワードを指定する必要がなくなり、
 構造体変数の宣言が簡単になる。
C > 基礎 | comments (0) | trackbacks (0)

enum

構文
enum タグ名 {
 列挙子1 = 定数, 列挙子2 = 定数 ...
} 列挙変数;



enum { MSG_OK, MSG_YESNO };
enum { ID_OK = 1, ID_YES, ID_NO };


タグ名と末尾の列挙変数の宣言は、構造体や共用体と同じように
省略することができる。


#include <stdio.h>

void main()
{
 enum { Sun,Mon,Tue };

 int x = Sun;
 switch ( x ) {
 case Sun:
  printf( "日曜日の処理" );
  break;
 case Mon:
  printf( "月曜日の処理" );
  break;
 case Tue:
  printf( "火曜日の処理" );
  break;
 }
}

C > 基礎 | comments (0) | trackbacks (0)

論理演算子

論理和
A||B

論理積
A&&B

否定
!A

排他的論理和
(A||B)&&!(A&&B)


・優先順位は!&&||となります。
&&||は左から右に評価されることが保証されています。
 そして条件が一致すれば、そこで条件判定を中止します。
 ですから合致する確率の高い条件を最初に記述した方が処理効率が良くなります。
C > 演算 | comments (0) | trackbacks (0)

ctime

char *ctime( time_t *time )

システムクロック時間を人間が理解可能な時間文字列に変換する。
ctimeとはconvert timeの略かと思われる。
意味合い的には「localtime+asctime」という働きをする。


#include <stdio.h>
#include <time.h>

void main()
{
 time_t nowtime;
 time( &nowtime );
 printf( "%s", ctime( &nowtime ) );
}


実行結果

Tue Oct 24 12:12:37 2006


'\n'と'\0'が文字列の最後に付加されます。
C > 標準関数 > 時間処理 | comments (0) | trackbacks (0)