C/C++」タグアーカイブ

C/C++ のポインタはコレさえ解ればいい

C 言語で何か作れる人にはどうでもいい話。
今となっては C/C++, C#, Python, PHP をゴチャマゼで利用している私ですが…
十年前は C 言語を勉強していて見事ポインタで挫折した人である。

ポインタは実態へのアドレス(以下略

って、そんなのは解っているよ!だからポインタをどう使えばソフトウエアが作れるんジャ!
という理由である、勝手な思い込みだけど似たような人は多いと思う。
こんな状態である人に解りやすく説明してくれている本やサイトは存在しない。

実はたった一つのことだけを気がつけばいいだけ。
以下のコードについて細かい説明は一切しない、初心者本を読んでくれ。

#include <stdio.h>

void plusfunc(int num1, int num2, int nResult)
{
    nResult = num1 + num2;
}

int main(int argc, char *argv[])
{
    int n1, n2, n3;
    
    n1 = 2;
    n2 = 3;
    n3 = 0;
    plusfunc(n1, n2, n3);
    printf("%d+%d=%d\n", n1, n2, n3);
    return 0;
}

コレを実行すると
2+3=0
と出力される、つまりコレじゃ関数で値を変更できないんだよ!
理由が解らない人は本で調べよう、だからポインタを使う。

#include <stdio.h>

void plusfunc(int num1, int num2, int* nResult)
{
    *nResult = num1 + num2;
}

int main(int argc, char *argv[])
{
    int n1, n2, n3;
    
    n1 = 2;
    n2 = 3;
    n3 = 0;
    plusfunc(n1, n2, &n3);
    printf("%d+%d=%d\n", n1, n2, n3);
    return 0;
}

これで 2+3=5 と正常な出力になる、と初心者本はこんな感じの説明をしていたと思う。
いや、このコードって何かおかしいだろ?余程のバカでなければこう書くはずだ。

#include <stdio.h>

int plusfunc(int num1, int num2)
{
    return num1 + num2;
}

int main(int argc, char *argv[])
{
    int n1, n2, n3;
    
    n1 = 2;
    n2 = 3;
    n3 = plusfunc(n1, n2);
    printf("%d+%d=%d\n", n1, n2, n3);
    return 0;
}

えっと、つまりポインタってどういう時に使えば使いこなせるの?
となってしまった、だから私はポインタが無い Delphi に一度逃げた…
という昔話はどうでもよくて。
int で説明するから理解できない、文字列で説明すればアッサリ理解できる。

#include <stdio.h>
#include <string.h>

void plusfunc(int num1, int num2, char* szResult)
{
    sprintf(szResult, "%d だよ!", (num1 + num2));
}

int main(int argc, char *argv[])
{
    int n1, n2;
    char szRes[16];
    
    n1 = 2;
    n2 = 3;
    strcpy(szRes, "0 かな?");
    plusfunc(n1, n2, szRes);
    printf("%d+%d=%s\n", n1, n2, szRes);
    return 0;
}

C 言語の文字列は = で代入できないので関数を使うしかない。
つまり = では値を変更できないものを変更する関数を作る時にポインタを使う。
それだけ、strcpy 等の標準関数だってやはりポインタを使っているわけです。

それに気がついただけでいつのまにか C 言語は書けるようになった。
もっと細かいことについては何か作っていれば自然と理解できているはず。

手持ちの本で int で説明されている部分を文字列に置き換えて読めば結構理解が早い。
どうしてプログラミング本って全部 int なんでしょう?int だから解らないのに。

main function

さてスッゲェ久々に Linux で C/C++ をやるか。

コンパイルするのがメンドクセェ、Python スクリプトでイイじゃん…
てか今更 ++ の無い C はどうも、class が利用できないなんて考えられない…
とは言わないで、基本は大事だから。

Mandriva One の人は gcc が入っていないので gcc-c++ をソフトウエア管理から入れよう。

なんか Ubuntu とは随分違うんだけど、Mandriva の java うんちゃらって何だろう?
とにかくコレで Mandrina One でも C/C++ のコンパイルができる。

ということで早速超最小限の C 言語コードを書いてコンパイルしましょう。

#include <stdio.h>

main()
{
    printf("はろぉわーるど\n");
}

コレを少し奇妙に思った人は最初をすっとばして勉強している人。
main 関数が値を返していない、引数が無い、でもこれでコンパイルは通るんです。
Windows で C をやっているなら知らない人はいない粂井氏や赤坂氏もコレで始めていますよ。
つまり Visual Studio でやっても同じ結果、return 0; は実は書かなくても良かったりする。

C言語編INDEX
C言語入門

main 関数は仮引数を持たない関数、又は 2 つの仮引数を持つ関数として定義される。

int main(void) { /*...*/ }
int main(int argc, char *argv[]) { /*...*/ }

返却値の無い場合のホストに返させる終了状態は未定義である。
と、私のバイブルである「新ANSI C言語辞典」に書いております。

新ANSI C言語辞典

とりあえず返却値はゼロが戻れば Windows も Linux も正常終了とホストが解釈する。
やたら詳しいページを見つけたのでリンクしておきます、envp なんて初めて知ったよ。
main – 通信用語の基礎知識

ということで CUI なら Linux でも Windows とあまり違いが無いと解りました。
後は粂井氏や赤坂氏のサイトで(ぉい!

いや、もう少しやると思うけど配列とかの基本は本や既存のサイトで十分だもの。
こういう少しヒネクレたネタのほうが私は好きなのです。

Ubuntu 9.10 には build-essential はイラン

アクセスログを見て見つけたが

Ubuntu9.10を使っています。 Cの勉強をしてみたいと思っているのですが、gccの使い方について教えてください。 ソース内に日本を含み、シェルでの出力にも日本語を伴う場合.. – 人力検索はてな

> http://palepoli.skr.jp/content/ubuntu/mono.php
> 統合環境を使ったほうがお手軽です。

いや…
C をまったく知らない人にイキナリ総合開発環境を勧めるのはどうかと。
そのページを書いた本人も十年前は Windows にて BCC で勉強していた人なんですけど。

というか Emacs で文字コードがどうのって普通に保存すれば local と同じにならないのかな?
local は UTF-8 なんだから bash も当然 UTF-8 で出力するわけで、とりあえず cat しろと。
なんか気になったので仮想の Ubuntu 9.10 を立ち上げて適当にコンパイルしてみる。

やっぱり問題無い。
return かセミコロン書き忘れとか超くだらない理由じゃないのかと疑ってしまう。

しかしおかげで気がついた。
Ubuntu 9.10 には build-essential はイラン、最初から gcc がありヘッダも揃っている。
と以前 Blog には書いたと思うけど覚書のページは昔のまんまや!
書き換えなきゃ…でも今は日本で人気が薄い Mandriva Linux がメインな私ですけど。

ところで、今でも PyGtk よか mono や c の覚書ページのほうがアクセスが倍以上のまま。
Google のおかげで Python 知名度は上がったけど初心者の大半は C/C++ 開発に憧れている。
と勝手に解釈している、基本は C 言語であるというのは同意だし絶対に勉強しておけ。
だけど何故か Y901x のダウンロード数は増えて今月は既に百を超えているのって不思議。

それより、なんたって初心者御用達な Ubuntu でのプログラミングですので…
楽をしようと Python/PyGtk からプログラミングに入ると寒いアプリが乱立しそう…
VB に ActiveX コントロールを貼り付けただけで工夫の無いアプリみたいなのが再現…

やはり Linux で C/C++ のページをキチンと作ったほうがいいかなと思ってきた。
オブジェクト指向っていうけどソレってつまり実態に見せかけただけのポインタですから。

Visual Studio x64 build test

時間が掛かりすぎるので休日にしかできない仮想 Vista 構築の続き。

前回はただ OS のインストールだけで終わったので Vista に SP を当てないと。
Windows Update では自動で当ててくれないのが忌々しい。

sp1 を当てないと sp2 が当てられないのね、面倒すぎ。
4 時間使ってやっと両方が終わったところで IE8 への自動更新が出る。
一度にやってくれよ、何回再起動させればいいのやら…

やっと Visual Studio をインストールする環境が揃う。
インストール DVD を立ち上げ今回は忘れずに「すべて」を選択。

vs_all

やっぱり一時間半掛かって、んで一時間使って MSDN ヘルプを入れて…
そして sp1 にするのにまた一時間半と、更に Update が掛かって…
そして今回も丸々一日使うはめになったとさ。

あーもうなるべくコイツは使いたく無い、Visual Studio 専用 OS にしよう。
FTP ができないと困るがこれでやればイイや。

[IE]Internet Explorer で FTP サイトのパスワードを入力する方法

Explorer のエディット部にコレやればとりあえずファイル転送はできるのよね。
パーミッション変更とかはできるはずがない、それらはホストの Mandriva からやる。
パスワードに記号とか入れている人は URI 変換をお忘れなく。
でも何故か Windows 7 ミニノートからではできない…

とにかく minipoli のソースを落として実験だ。
Visual Studio 起動、初回は遅いけど二回目以降は起動が早いというより一瞬。
仮想 OS になっても Vista の SuperFetch は完璧である。
でなきゃ困る、だから XP も 7 も持っているのに Vista を使うんだから。
7 の SuperFetch は効きがイマイチなんだよなぁ…

select_x64

「すべて」を選択したので今回はしっかり x64 の選択肢があった。
ソースコードはまったく弄くらずに minipoli をビルド、何事もなくビルド完了。
ちょっと拍子抜け、本当に 64bit 用にビルドされたのかな?
実験で 32bit であるこの Vista で使ってみる。

minipoli64.zip

32bit_test

わーい 64bit ですってエラーになった!
次に x64 Windows 7 であるミニノートに持っていき試す。

64bit_test

あたりまえのように動く、マジでコードは一行も変更しないで済みそうだ。
後は 64bit 用インストーラを作成すれば minipoli の x64 化は完了。
それがやりたいだけの為に二回も休日を全部使ってしまった…
好きでやっているのだから別にイイのだが。

OSASK 公開停止か? – スラッシュドット・ジャパン

いやいや、皆が何を言いたいかよく解るなぁ。
開発者が望んでいるようなユーザーが一人でもいるなんて奇跡に等しい世界ですから。
情報公開もオープンソースも自己満足、それでいいじゃない。

Windows でもゴミ箱

Linux ばかりに触っていたらマニアックになるので Windows を久々に。

せっかくゴミ箱について興味をもったので Windows でも色々調べてみる。
OS の仕様としてゴミ箱を持つ Windows ではコマンドとかはどうなっているのかな?

コマンドプロンプトでごみ箱へファイルを移動させるにはどうすればよいのでしょうか? -OKWave

XP では c:\recycler 以下のはずだけど…てかドライブ毎ユーザー毎に存在するんだが何時の話?
試しにやってみた、ごみ箱に残らないとか書いているけどつまりこうなっているだけだと思う。

cmd_move

アプリを紹介しているけど VC++ を持っているならの SHFileOperation を使って簡単に作(略
なんにせよ Windows でも Shell API からしかアクセスできないんだ、ふむふむ。

OS 非依存の仮想マシンであるはずの .NET Framework はどうなのかな?

ファイルをゴミ箱へ削除(C#)について – Insider.NET

やはり P/Invoke でアクセスしなさい!にしているようで。
そんな糞面倒なことをするより VC++ でラッピングした dll を作って(略
それにしても「がっかり」って人… .NET Framework が何なのか解っているのかな?

Python は…当然 gio モジュールなんか使えるはずもなく。
これも VC++ でラッピングした dll を作って(もういいよ

Windows Power Shell なら結構簡単に

Windows Script Programming: PowerShellでファイルやフォルダをごみ箱に捨てる。

全然簡単じゃネェ!デフォルトで手段を用意してくれている分マシなだけだ。

うわぁ…つまりシェルてかこの手のことをやろうとすると VC++ が必要になるわ。
ま、こんなことを書いたしせっかくなのでゴミ箱へ送る DLL の作り方を書いておこう。
Visual Studio の入っている Vista の HDD に繋ぎ替えて…メンドクサ。

VisualStudio を起動する、VC++ Exp でも同じはず。
trash という名前の新規 Win32 コンソールプロジェクトを作る。
ウイザードを進めてアプリケーションの種類を「DLL」にして完了。
そして Python から使う場合にはまずやらなきゃいけないこと。

stdcall

と呼び出し規約を __stdcall にする、意味は勝手に調べてね。
達人なら違うと言うだろうけど普通の人ならそれ以外はデフォルトのままでいい。
つまりデフォルトの UNICODE ビルドだが今はそのほうが自然だろう。

追記
忘れていた!Releace 版だけでいいんだが
コード生成のランタイムライブラリを「マルチスレッド」にして。

multi

「マルチスレッド DLL」のままだと VC9 ランタイムも配らなきゃいけなくなる。
7kb が 41kb に増えるけどこれで DLL 単体で配布できるようになる
VC++ が入っている環境だと普通に動くので忘れがちなんですよねココ。
追記おわり

stdafx.h の最後の行に下記を追記

#include <shellapi.h>

コード

#include "stdafx.h"

extern "C" __declspec(dllexport)
BOOL trash(LPCWSTR szFileName)
{
	SHFILEOPSTRUCT sfos;
	ZeroMemory(&sfos, sizeof(SHFILEOPSTRUCT));
	wchar_t szOpFile[1024];
	wcscpy_s(szOpFile, 1024, szFileName);
	szOpFile[wcslen(szOpFile) + 1] = L'?0';
	sfos.hwnd = NULL;
	sfos.wFunc = FO_DELETE;
	sfos.pFrom = szOpFile;
	sfos.fFlags = FOF_SILENT | FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
	if (!SHFileOperation(&sfos))
	{
		return TRUE;
	}
	return FALSE;
}

trash.zip

DllMain を書いて Visual Studio 2008 でビルドしたら警告になった。
分離されているのか、targetver.h といい親切なのか余計なお世話なのか。

細かいことは→の「APIで学ぶWindows徹底理解」に書いています。
ちなみに私が買ったこの本はもう読み直ししすぎてボロボロです。

後はそのままビルドで DLL の完成。
Python.exe があるディレクトリに trash.dll をコピーします。

exp

ここまでくれば python からは毎度のように ctypes を利用して

import ctypes

dll = ctypes.windll.trash
if dll.trash("C:\\Python30\\gomi.txt"):
    print("ok")
else:
    print("miss")

こんな感じであっさりゴミ箱へ捨てられます。
2.* ではファイル名を UNICODE にするのをお忘れなく。
どうしても Python でやらなきゃいけない場合以外は VC++ で作ったほうが(略