2010年04月25日

Seesaaブログの独自タグ内で使用可能な演算を調べてみた。

実は、独自タグ内では算術演算が可能だ。何処まで可能なのか、ハッキリと調べた訳ではないが、加算(+);、減算(-)、乗算(*)が可能なのは確認した。

……と、Seesaaブログの独自タグ <% if %> で、論理演算する方法で書いたが、ちょっと突っ込んで調べてみた。まぁそこそこ一般的に有りそうな演算子で。もちろん他にもある可能性はあるので、誰か知ってたら教えてくだちぃ。

四則演算

と、剰余演算。剰余演算が通るとは思わなかった。加算減算以外の有効な利用法が思いつかない……

コード出力結果
<% echo(1 + 2) %>3
<% echo(2 - 1) %>1
<% echo(1 - 2) %>-1
<% echo(2 * 3) %>6
<% echo(4 / 2) %>2
<% echo(3 % 2) %>1

等号不等号、比較演算

結果が偽になるものは、何も出力されない。真で1が出力されるので、てっきり0かと思っていたので吃驚した。内部的には、nullとかundefinedといった種類の値なんだろうか?特に実害はないようだが。

コード出力結果
<% echo(1 == 1) %>1
<% echo(1 == 2) %>
<% echo(1 != 1) %>
<% echo(1 != 2) %>1
<% echo(1 < 2) %>1
<% echo(1 <= 1) %>1
<% echo(2 > 1) %>1
<% echo(1 >= 1) %>1

文字列比較

文字列の比較には、eqneを使う。==!=ではない。

コード出力結果
<% echo('foo' eq 'foo') %>1
<% echo('foo' eq 'bar') %>
<% echo('foo' ne 'bar') %>1

<% if %>の条件判断について

早い話が、「非0は全て真になるのか?」の確認。

一番最後のは、「偽と0を比較したらどうなるか?」を確認している。

コード出力結果
<% if:(1 + 0) %><% echo('TRUE') %><% /if %>TRUE
<% if:(0 + 0) %><% echo('TRUE') %><% /if %>
<% if:(2 + 0) %><% echo('TRUE') %><% /if %>TRUE
<% if:(1 - 2) %><% echo('TRUE') %><% /if %>TRUE
<% if:((1==2) == 0) %><% echo('TRUE') %><% /if %>TRUE

詳細不明

Seesaaブログは、文法エラーになると、そのコンポーネントは丸々出力されなくなるので、少なくとも以下の記述は正しいものだと思われる。ただし、どういう意味なのか不明。

文字列の文字コードによる比較かと思ったが、そうではないらしい。必ず真になっている。

コード出力結果
<% echo('1foo1' lt '2foo2') %>1
<% echo('2foo2' lt '1foo1') %>1
<% echo('1foo1' lt '1foo1') %>1
<% echo('foo1' gt 'foo2') %>1
<% echo('foo2' gt 'foo1') %>1
<% echo('foo1' le 'foo2') %>1
<% echo('foo1' ge 'foo2') %>1

その他

累乗は不明(^ではなかった)、ビット演算は不可、所謂宇宙船演算子無し、8進数/16進数表記不可。

文字列連結はどうやるのだろう?まぁ、必要なさそうな気もするが。

posted by 天井冴太 at 04:31| Comment(0) | TrackBack(1) | Study | 更新情報をチェックする

2009年12月08日

WSHの各種オブジェクトのメソッドはどうやらfunctionではないらしい

WSH(wscript.exe或いはcscript.exe)と、XULRunnerのjs.exe(或いはxpcshell.exe)でのJavaScript(JScript)実行時の違いを確認したくて、ちょっとしたコードを書いた。

それぞれ文字列出力用メソッドが異なり、以下のようになっている。

WSH
WScript.Echo
XULRunner
print

毎回書き直すのもアホくさいので、以下のように書いてみた。

if(typeof print === 'undefined') { print = WScript.Echo; }

// ここから下にテスト用コード

もはや何の説明も要らない程単純なコード。で、WSH環境で実行してみる。

D:\Documents and Settings\amaisaeta\test_error.js(1, 36) Microsoft JScript 実行時
エラー: オブジェクトでサポートされていないプロパティまたはメソッドです。

あるぇ?

XULRunner環境下では勿論問題ない。36行目といったら、print = WScript.Echo;の部分。意味が分からん。

少し悩んで、WScript.Echo(typeof WScript.Echo);を実行してみた。

unknown

あるぇ?
"object"でも"function"でもなく、unknown?

……確かによく考えてみたら、WSHの各種オブジェクトはActiveXオブジェクトだったような

で、ググってみると、

最速の人の大昔のエントリに書いてあるんですけど、

IEのActiveXObjectっていうのはちょっと特殊で、メソッドなんかがJavaScriptのfunctionではない。

var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
alert(typeof xmlhttp.open); // unknown

こうなる。xmlhttp.openはfunctionではなくて謎オブジェクト。

IEでXMLHttpRequestを使えるようにする

つまりunknownってのはメソッドだと思って良いハズ。

という記述を発見
つまりunknownってのはメソッドだと思って良いハズ。とあるが、
"unknown"はメソッド("function")に似て非なるナニモノか
と考えといた方が良いのかもしれない。

つまり、

// if(typeof print === 'undefined') { print = WScript.Echo; }
// これを……
if(typeof print === 'undefined') { print = function(arg) { WScript.Echo(arg); } } // こうする

こうか。
最も、これだと1引数しか渡せない。可変長引数を更に別関数に渡したい時ってどうやれば良いんだろう……?

ActiveXオブジェクトだったような
COMオブジェクトだったかもしれない。どっちでもいいや。
ラベル:WSH JScript javascript
posted by 天井冴太 at 21:52| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2009年06月05日

JavaScriptの変数の面白い特性――グローバルな変数はundefined??

これは驚き。もしかしたら日頃JavaScript弄ってる人にとっては常識なのかもしれないけど、俺は凄く驚いた。

先ずは以下のコードを。


<html>
	<head>
		<script type="text/javascript">
			// <![CDATA[
			var hoge = 'hoge global';
			var piyo = 'piyo global1';

			if(piyo == undefined) {
				var piyo = 'piyo global2';
			}

			function f1() {
				var elem = document.getElementById('elem');

				elem.innerHTML = elem.innerHTML + '<br />' + piyo;
			}

			function f2() {
				var elem = document.getElementById('elem');

				elem.innerHTML = elem.innerHTML + '<br />' + hoge;
			}

			function f3() {
				var elem = document.getElementById('elem');

				if(hoge == undefined) {
					var hoge = 'hoge local';
				}

				elem.innerHTML = elem.innerHTML + '<br />' + hoge;
			}

			// ]]>
		</script>
	</head>
	<body>
		<p id="elem"></p>
		<script type="text/javascript">
			// <![CDATA[
			f1();
			f2();
			f3();
			// ]]>
		</script>
	</body>
</html>

で、この実行結果は、こうなる。


piyo global1
hoge global
hoge local

f1()は、続くf2()f3()との比較の為に書いているに過ぎない。ここで見て欲しいのはf2()f3()の実行結果の違いだ。

そう、グローバル領域で初期化している変数が、関数内ではundefiendと等価である、と評価されている

f1()

順に見てみる。先ずはf1()


var piyo = 'piyo global1';

if(piyo == undefined) {
	var piyo = 'piyo global2';
}

function f1() {
	var elem = document.getElementById('elem');

	elem.innerHTML = elem.innerHTML + '<br />' + piyo;
}

グローバル変数piyoを初期化。その直ぐあと、関数の外でpiyoundefinedか判定。当然、偽となるので改めて初期化されることはない。結果、f1()では最初に初期化した時の内容であるpiyo glocal1が出力される。

f2()


var hoge = 'hoge global';

function f2() {
	var elem = document.getElementById('elem');

	elem.innerHTML = elem.innerHTML + '<br />' + hoge;
}

単純にグローバル変数hogeを出力している。問題なくhogeの値であるhoge globalが出力されていることに注意。つまり、(当たり前のことだが)関数内からグローバル変数の値を評価できている。

f3()


var hoge = 'hoge global';

function f3() {
	var elem = document.getElementById('elem');

	if(hoge == undefined) {
		var hoge = 'hoge local';
	}

	elem.innerHTML = elem.innerHTML + '<br />' + hoge;
}

グローバル変数hoge(これはf2()で用いたものと同じ変数)を出力する前に、グローバル変数hogeundefiendでないかを評価、それが真ならば改めてhogeを(グローバルでとは別の値で)初期化している。そして、驚くべき事にこの評価式は真となっている。確かにグローバル領域で初期化しているのに!

f2()での結果を見ると、確かに初期化され、値を評価できているグローバル変数だが、f3()での結果によると、初期化されていないという評価を下されている事が分かる。言ってみれば、グローバル変数が、関数内ではundefinedと実際の値という2つの値を持っているかのようだ。

因みに、この動作は手持ちの以下のブラウザで確認した。すべでこの動作だった。(全てWindows用。Safariを除いて全て日本語版)

  • Mozilla Firefox 3.0.10
  • Opera 9.6.4 Build 10487
  • Safari 4 Public Beta (528.16)
  • Microsoft Internet Explorer 8.0.6001.18702

一体全体、これはどういう事なのだろうか。

ラベル:javascript
posted by 天井冴太 at 05:09| Comment(3) | TrackBack(0) | Study | 更新情報をチェックする

2009年04月26日

JavaScriptでhead要素を取得する方法

天井冴太的つれづれblog [天井の染み]: ffbadge.js - FriendFeedに登録しているサービスを一覧表示するブログパーツで公開しているffbadge.jsを作った時に嵌ったこと。

JavaScriptで、XHTML/HTMLbody要素を取得したい時には、こうする。


var hoge = document.body;

……って事は、head要素取得する時ってのはこうに違いない、と何の疑問もなく書いたコードがこれ。


var hoge = document.head;

hogeundefinedになって、どう頑張ってもhead要素が取得出来ない。何故だ……と思っていろいろ検索。 したらば、css + javascript の質問です。 javascript 中で css (外部ファイル) を読み込みたいと思っています。 そこで以下のような javascript を書いてみました。 var cs = docume.. - 人力検索はてなに書いてあった。


var hoge = document.getElementsByTagName('head')[0];

あー、document.headって無いのね……bodyがあるからheadも在るものとばっかり……

posted by 天井冴太 at 04:41| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2008年01月19日

Visual Basic 6でMBCS文字列処理

VB6って文字列基本Unicodeなのね。C言語でstrlen()したときみたく、全角文字=2文字、半角文字=1文字で計算して欲しい。


Dim Str As String
Str = "全角Hankaku"

Debug.Print Len(Str)    '  9
Debug.Print LenB(Str)   ' 18

上のコードでLen()が文字列長を返す関数。LenB()はそのバイナリ版。Len()だと全角半角関係無く1文字と数えるし、LenB()だと1文字2バイト消費なんでLen()の2倍の値が返る

困ってたらVS6.0付属のMSDNライブラリにLenMbcsと言う関数で実装例が載っている事を教えてもらった。勤務先でやった事だし、手元(自宅)にVS6のMSDNライブラリ無いんでうろ覚えだけど、確かこんな感じだった。


Public Function MidMbcs(ByVal str As String)
    MidMbcs = LenB(StrConv(str, vbFromUnicode))
End Function

おー、StrConv()スゴス。これって応用利かね?たとえばこんな感じで。


Public Function MidMbcs(ByVal Str As String, Start As Long, Optional Length As Long = &HFFFFFFFF)
    MidMbcs = StrConv(MidB(StrConv(Str, vbFromUnicode), Start, Length), vbUnicode)
End Function

つかこういう事するんならVBなんかよりC言語使った方がいい気がしてきた。

posted by 天井冴太 at 23:29| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2008年01月14日

Visual Basic 6のクラスモジュール内で発生させたエラーが取得できない件

久々の更新はメモ書き風味。

何のことかといえば、VB6で

Public Sub s()
    Err.Raise vbObjectError
End Sub

……なんてクラスを定義して、

Dim c as Class1
Set c = New Class1

On Error Goto ErrHandler
c.s ' エラーが発生して、ErrHandler以下に処理が移ることを期待

ErrHandler:
' エラー処理ごにょごにょ

……しても、ErrHandlerに処理飛ばないで、エラーで落ちる。なんでやねん。ワケ解らん。

んで、検索したらこんなページが引っかかった。

その場合は、呼び出し側にて On Error を使って、例外処理を行うようにしてみてください。
なおその場合、VBのエラートラップモードを、既定の「クラスモジュールで中断」から、
「エラー発生時に中断」にしておく必要があります。
# エラートラップモードを変更しておかないと、開発環境での実行時では、
# クラス内のErr.Raise部で、実行が中断されてしまいますので。

うーん、多分これだろうなぁ。今手元にVB6ないから確認できないけど。しかし、エラートラップモードなんて有ったっけ?

posted by 天井冴太 at 20:12| Comment(2) | TrackBack(0) | Study | 更新情報をチェックする

2007年04月02日

DirectInput8Create()がE_POINTERを返してきた話

DirectX SDKでプログラミング中、キー入力処理部分を実装する為にDirectInput8Create()を呼び出すコードを書いた。


LPDIRECTINPUT8 dinput;
HRESULT hResult = DirectInput8Create(
    GetModuleHandle(NULL),
    DIRECTINPUT_VERSION,
    IID_IDirectInput8,
    reinterpret_cast<LPVOID *>(dinput),
    NULL
);

こんなかんじで。

さて実行、と動かしてみると、絶対に失敗する。しかも、リファレンスにも記述されてないE_POINTERを返してくる。んー?何でー?

どんなに睨んでも原因が分からない。しょうがないのでGoogle先生にお伺いを立ててみると……

When run, it doesn't return any of the possible return values for DirectInput8Create(), instead DirectInput8Create() returns E_POINTER (An invalid pointer, usually NULL, was passed as a parameter).

全く同じ現象で悩んでる人を発見。英語だけど仕方ない、愛用のFirefox拡張機能翻訳パネルbackwordの力を借りて読み進んでみる、と、

Maybe:

hr = DirectInput8Create(p_Config.hinst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&DInput, NULL);

(  д ) ゜ ゜

うわ、すげー馬鹿ミス。

しかし凄いなぁ、キャストしてるのにエラーが出るんだ。コレってつまりどっかに型情報を持たせているって訳だし。もしかしたらMicrosoft社のC/C++コンパイラ限定の機能なのかもしれないけど。

つか、頼むからそういうケースがあるならドキュメント化しといて欲しかったり。もしかして他のDirectXコンポーネントの初期化関数(Direct3DCreate9()とか)もE_POINTER吐くんだろうか。未確認だけど。

posted by 天井冴太 at 22:51| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2007年02月07日

リンク出来ない!?

2日程引っ掛かったのでメモ。

自作の静的ライブラリをプログラムにリンクしようとして問題が発生した。いや、コンパイルは通るのだが、リンクでコケるのだ。

以下、Visual C++ 2005 Express Editionで起きたリンクエラー。

msvcprtd.lib(MSVCP80D.dll) : error LNK2005: "public: char const * __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::c_str(void)const " (?c_str@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEPBDXZ) は既に HOGEHOGE.lib(PIYOPIYO.obj) で定義されています。

何じゃコリャ。訳が分からん。うーん……

調べてみると、msvcprtd.libはVC++2005EEのC++用のマルチスレッドDLLインポートライブラリ。std::string::c_str()が多重に定義されている……ねぇ、標準ライブラリがヘンだと言われましても……

待てよ、そういえばstd::stringstd::basic_stringtypedefで、std::basic_stringはテンプレートクラスだ……。テンプレート関係はテンプレート引数の型が決まる(コンパイル時)迄バイナリコードは作りようが無い筈……つまり自作ライブラリ作成時に生成されたstd::stringのコードと今回のプログラム内のstd::stringのコードが、全く同じ内容なのに別の(同名の)クラスと捉えられている……という事か!?






…………って、ンな訳無いだろ!
いくらなんでも。そんなとんでもなく不便な。……うーーん?

……今にして思えば、ここでもうドツボ。簡単に解決できるだろうとタカを括っていたのが災いしてしまった。

2日試行錯誤しても一向に解決しないので、しぶしぶGoogle先生にお伺いを立ててみた。

スタティックライブラリ作成時の「使用するランタイムライブラリ」(*1)と
使用側の「使用するランタイムライブラリ」が一致してない場合にこのエラーが出ます。

回避方法としては、使用側の「使用するランタイムライブラリ」と同じ値を
スタティックライブラリ側の「使用するランタイムライブラリ」に指定します。


*1 : 「プロジェクトの設定」→「C/C++」→「コード生成」の所にあります。

げ、設定!?そんな設定弄った記憶無いんだが……

調べてみると、ヤッパリその通り。うーん、何時変わったんだろう……

教訓

  • 意地を張らずにサッサとググれ
  • 弄った記憶が無い部分も疑え
ラベル:C C++ Visual_C++
posted by 天井冴太 at 20:19| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2007年01月02日

友達宣言の仕方――名前空間内のクラスから名前空間外のモノをfriend宣言

オブジェクト指向の概念を取り入れたC++にはfriendという構文が在る。他のクラスや関数から非publicなメンバの利用を許可する『親友をつくる』機能だ。例えば次のコードはエラーとならない。


class A {
    // Bクラスをフレンドクラス宣言
    friend class B;

    // gf_getAm関数をフレンド関数宣言
    friend int gf_getAm(A &a);

private:
    int m_;
};

class B {
    int getAm(A &a) {
        // BクラスからAクラスのprivateメンバにアクセス出来る.
        return a.m_;
    }
};

int gf_getAm(A &a)
{
    // gf_getAm関数からAクラスのprivateメンバにアクセス出来る.
    return a.m_;
}

今回はそんなfriendに関する話。

名前空間外へfriend

例によって例のごとく、C++でプログラミング中の私、天井冴太。ある名前空間内のクラスでグローバルスコープのクラスをフレンドクラスに宣言したい。なので次のように書いた。


namespace ns {
    class C1 {
        friend class C2;
        int i;

    public:
        C1(int a) : i(a) {}
    };
} // namespace ns;

class C2 {
public:
    void set(ns::C1 &c1, int a) { c1.i = a; }
    int  get(ns::C1 &c1) { return c1.i; }
};

Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.
test.cpp
test.cpp(13) : error C2248: 'ns::C1::i' : private メンバ (クラス 'ns::C1' で宣言されている) にアクセスできません。
        test.cpp(4) : 'ns::C1::i' の宣言を確認してください。
        test.cpp(2) : 'ns::C1' の宣言を確認してください。
test.cpp(14) : error C2248: 'ns::C1::i' : private メンバ (クラス 'ns::C1' で宣言されている) にアクセスできません。
        test.cpp(4) : 'ns::C1::i' の宣言を確認してください。
        test.cpp(2) : 'ns::C1' の宣言を確認してください。

test.cpp: In member function `void C2::set(ns::C1&, int)':
test.cpp:4: error: `int ns::C1::i' is private
test.cpp:13: error: within this context
test.cpp: In member function `int C2::get(ns::C1&)':
test.cpp:4: error: `int ns::C1::i' is private
test.cpp:14: error: within this context

あれ?変だな?……名前空間が悪さしてるのかな?friend class C2;::C2では無くns::C2を探しに行ってしまっているとか?

という訳で、friend class C2;friend class ::C2;に変更してみる。

コンパイル……よし、VC++ 2005のコンパイラは通った。GCCはどうだ?


test.cpp:3: error: expected type-name
test.cpp:3: error: friend declaration does not name a class or function
test.cpp: In member function `void C2::set(ns::C1&, int)':
test.cpp:4: error: `int ns::C1::i' is private
test.cpp:13: error: within this context
test.cpp: In member function `int C2::get(ns::C1&)':
test.cpp:4: error: `int ns::C1::i' is private
test.cpp:14: error: within this context

うーん、エラーが取れない。むしろ増えてるんですけど……


test.cpp:3: error: expected type-name
test.cpp:3: error: friend declaration does not name a class or function

……の部分がアヤシイ気がする。小一時間悩んでコードの先頭にclass C2;を追加してみる。……ま、無理だろうけど…………通ったよ

つまるトコ最終的に以下のようなコードに。


class C2;
namespace ns {
    class C1 {
        friend class C2;
        int i;

    public:
        C1(int a) : i(a) {}
    };
} // namespace ns;

class C2 {
public:
    void set(ns::C1 &c1, int a) { c1.i = a; }
    int  get(ns::C1 &c1) { return c1.i; }
};

……って、ええぇぇぇ。1行目にclass C2;が必要なんて、チョットどうよ。美しくないぞ。friend宣言部分だけで何とかならんのか?

関数だと?

ココでふと疑問。クラスはこれで上手くいったが、じゃあ関数の場合は?

試しにC1::iにアクセスするグローバル関数を作成。上記コードclass C2;の部分をそのプロトタイプにしてみた。


int f();
namespace ns {
class C1 {
    friend int f();
    int i;

public:
    C1(int a) : i(a) {}
};
} // namespace ns;

int f()
{
    ns::C1 c(1);
    return c.i;
}

Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
test.cpp(23) : error C2248: 'ns::C1::i' : private メンバ (クラス 'ns::C1' で宣言されている) にアクセスできません。
        test.cpp(7) : 'ns::C1::i' の宣言を確認してください。
        test.cpp(4) : 'ns::C1' の宣言を確認してください。

あれー、通らないfriendが認識されてない。

チョット考えてfriend int f();friend int ::f();に変更してみた。……よし通った。

……って、クラスだと::無くて良くて関数だと必要ってどうよ。統一感無いなぁ。……もしかして規格上はどちらの場合でも::要るんだろうか?VC++GCCも規格外の動きをしているだけで。試しにクラスへのfriend宣言のコードfriend class C2;friend class ::C2;にしてもコンパイル通ったし。どうなんだろう。

JISでのfriend

ところで、今回このエントリを書くにあたってJISのC++規格書(JISのサイトからX3014で検索して出てくるヤツ)を覗いてみたが、JIS C++規格ではfriendの事を『随伴』と表現している事を初めて知った。……んー、『随伴』ねぇ……『friend』の単語から受けるイメージとズレるなぁ……

ラベル:C++
posted by 天井冴太 at 21:17| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2006年12月05日

#演算子で困った!!

C/C++にはソースのコンパイルの前にプリプロセスと呼ばれる処理が入る。#include#define等、#記号で始まる行の処理によって、そのソースの(コンパイラに渡す)内容を変更する事が出来る機能だ。例えば前出の#includeは任意ファイルの内容をそのソース内に埋め込む処理、#defineはそれ以降のソース内に存在する任意文字列を別の文字列に変換する事が出来る

え!?#演算って制限があるの!?

#defineには特殊な演算子として#というものが在る。オペランドを文字列化するという機能だ。例えば次の関数マクロは引数を文字列化し、それを返す。


#include <stdio.h>

#define TOSTR(x) #x

int main()
{
    puts(TOSTR(hoge));	// 結果を出力
}

hoge

さて、ある日__LINE__を1つの文字列として取得したい、という状況になった。で、書いたのが以下のような感じのマクロ。


// argには文字列が来る(という想定)。
// C/C++では連続する文字列リテラルは1つの文字列リテラルとして処理されるので、
// ↓のような記述で構わない。
#define M(arg) ((arg) #__LINE__)

行番号(整数)である__LINE__を文字列化する為に#演算子を使っているのが分かると思う。

早速コンパイルしてみる。


testsharp.c(7) : error C2162: 文字列化演算子 (#) の後のトークンは、仮引数名でなければいけません。

え!?そうなの!!?
手元にあった新 ANSI C言語辞典改訂版 独習C新C++言語入門 シニア編(上) 基本機能を見てみたが全っ然それっぽい記述が無いんだが。

試しにGCCのversion 3.4.2 (mingw-special)、ついでにVC++6.0でも試してみたが、やはりエラーとなった。うーん。

__LINE__が展開されない!!

まぁそれぐらいは上の例で挙げたTOSTR()のようなマクロを作って、#__LINE__としている所をTOSTR(__LINE__)とすればいいだろう。チョコチョコッと弄って、さぁ完成!


puts(M("test"));
// 期待する出力結果(ファイル名はhoge.c、上記puts()が10行目に在ると仮定):
//  test10

test__LINE__

( д ) ゚ ゚
__LINE__が展開されてNEEEEEEEEEEE!!

いやまぁ、そりゃ#がオペランドの文字列化を行うならば、TOSTR(__LINE__)"__LINE__"に展開されても別におかしくはない__LINE__の展開よりユーザ定義マクロの方の展開が優先される、という訳か……

さて困った。うーん、どうしよう……

#include……
#include,#define双方ともそれだけの機能ではないが、取りあえず代表的なものを挙げた。
関数マクロ
#defineで定義したものをマクロというが、それの関数風のもの。例えば、#define ADD10(arg) ((arg) + 10)と定義し、int a = ADD10(1);とソース中に記述した場合、aの値は11となる。
__LINE__
もC/C++で前以て定義されている組み込みマクロの1つで、それが記述されている行の行番号に展開される。
ラベル:C C++
posted by 天井冴太 at 21:22| Comment(2) | TrackBack(0) | Study | 更新情報をチェックする

2006年11月25日

ブラウザでの任意改行――wbrでなくて&amp;shy;の話――

前回の長い文字列を自動的に途中改行させるようにするJavaScript - Firefoxで長い文字列が改行されない件を回避しようとして翻弄された話今度(多分)纏めますとしていた部分の話。1週間以上ブランクが在るのは気にしてはいけない。いいえバグではありません仕様d(ry

その条件分岐部分を抜き出してみたのが下記。


// UA別に処理を振り分け
if(navigator.userAgent.indexOf("Gecko") == -1) {
    nNode = document.createTextNode("\xad");    // &shy;
} else {
    nNode = document.createElement('WBR');
}

軽く解説すると、navigator.userAgentにはUA(例えばwebブラウザ)の名称(とかOS名とか)が入っている。indexOf()は対象文字列に引数で指定した文字列がある位置を返す関数で無い時は-1を返す。Mozilla系ブラウザ(Firefoxとか)はGeckoというレンダリングエンジンを使っているのでそれを判定材料としている。で、Mozilla系UAではwbr要素を、それ以外では文字コード0xadを書き込んでいる。

wbr前回説明した通り。じゃあ0xadって何さ??という話。

­ ――standardな任意位置途中改行――

前回スクリプトを組むときに悩んだのがwbr要素が非標準だという事。便利なのかもしれないが、出来れば標準規格に則った記述がしたい。何か無いか……と探していて見つけたのが&shy;ソフトハイフンを挿入する為の文字参照だ。

shyなやつ - 徒書長い文字列の改行方法 - wbr, ­, css - World Wide Walkerにて解説されているが、 ソフトハイフンとはユーザエージェントに対し、そこが行区切りが発生してもよい場所であることを示すものである。との事。……つまり、wbrの代わりに&shy;(又は&#xAD)使えば標準規格から外れる事も無く期待通りの機能が実装出来るぜヒャッホゥイ!!

と思ったら……さてかんじんのMozillaではというと、((略))全く改行されずに遙か右方に伸びていってしまいます……Mozilla対応して無いのね……

正直IEが対応していてFirefoxが対応していないというのは激しくムカツク訳だが、とりあえずMozilla系以外のUAではwbrで無くソフトハイフンを入れるようにした。

……てか、document.createTextNode()ってdocument.write()と違って文字参照って書けないのね。そっくりそのままの内容のテキストになる。しょうがないので、文字コードで指定しているが。

ところで、Firefox。

&shy; は ((略))Firefox ではそもそも全く無視されているようだ。

……と、長い文字列の改行方法 - wbr, ­, css - World Wide Walkerでは書かれているが、一応認識はしているようだ。

その証拠(?)にshyなやつ - 徒書でテストとして書かれているクソ長い英単語をFirefox2.0で選択、テキストエディタにペーストしてみると、­挿入位置毎に"-"が表示される。

参考

Mozilla系ブラウザ(Firefoxとか)はGeckoというレンダリングエンジンを使っているのでそれを判定材料としている
正直ココは手抜き。レンダリングエンジンはあくまで描画の為のものなので本当は正しく無いんだろうなぁ。
posted by 天井冴太 at 00:01| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2006年11月09日

MSに翻弄された話

標準規格 != Microsoft実装

ある日ふと思い付いて、とあるコンテナクラスを作ってみようと思った。言語はC++、チョット特殊なマップコンテナだ。STLのコンテナと互換に作っておけば後々便利だろう。作った事無いけど。

とは言え、STLのマップについて熟知しているとはいえない。色々資料を参考にしながら制作する事にした。

さて、何から始めたものか……そうだ、とりあえずstd::map互換の型定義をしてしまっておこう。

私は日頃リファレンスとしてMSDNライブラリ日本語版の2001年10月リリース分を愛用している。キーワードによるインクリメンタルサーチや全文検索

、ブックマーク機能とHTMLヘルプは便利だ。より最新のVisual Studio 2005 MSDN ライブラリもいいが、アレは標準関係が英語だしかなり重いし。

……で、MSDNライブラリ日本語版の2001年10月リリース分のstd::mapの項を参考に次のような骨組みを作った。


template<typename Key_, typename Value_, typename Comperer_ = std::less<key>,
    typename Allocator_ = std::allocator<std::pair<Value_> > >
class Map {
public:
    typedef Key_ key_type;
    typedef Value_ referent_type;
    typedef Comperer_ key_compare;
    typedef Allocator_ allocator_type;
    typedef std::pair<key_type, reference_type> value_type;

public:
    class value_compere
        : public std::binary_function<value_type, value_type, bool>
    {
    };
    typedef allocator_type::size_type size_type;
    typedef allocator_type::difference_type difference_type;
    typedef allocator_type::rebind<value_type>::other::refrence reference;
    typedef allocator_type::rebind<value_type>::other::const_reference
        const_reference;
    class iterator;
    friend iterator;
    class iterator
        : std::iterator<std::bidirectional_iterator_tag, defference_type>
    {
    };
};

……と、此処まで書いて気になった。あれ?確かtemplate引数のアロケータのデフォルト引数ってstd::allocator<std::pair<const Key_, Value_> >じゃ無かったっけ……?

……確かにMSMSDNライブラリは便利だが、標準規格への準拠度という意味では全く信用出来ない非標準の機能を勧める警告をコンパイラに吐かせるような企業だし……。

……気になる。という訳で幾つかの文献で調べてみた。

資料とそれに載っているallocatorの形式
資料形式
MSDNライブラリ日本語版の2001年10月リリース分allocator<Value_>
新C++言語入門 シニア編(下) クラス機能399頁allocator<Value_>
http://www.wakhok.ac.jp/~sumi/stl/header/map.html#templateallocator<pair<Key_, Value_> >
Microsoft Platform SDK for Windows Server 2003 SP1のヘッダallocator<Value_>
gcc version 3.4.2 (mingw-special)のヘッダallocator<pair<Key_, Value_> >

ますます分からなくなってきた。結局ドッチなんだ?
仕方ないので、FDISを参照してみる事に。英語は苦手なんだけどね……。

template <class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T> > > class map;

うーん、という事はヤッパリallocator<pair<Key_, Value_> >の形式が正しいんだろうか……もういいや、FDISに合わせちゃえ。

あれー?まだ相違点がー!

何となくではあるが、とりあえず解決、解決っと。で、つれつれとFDISを眺めていると……

((略)) template <class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T> > > class map { public: // types: typedef Key key_type; typedef T mapped_type; ((略))

……mapped_type?
あれ?確かMSDNライブラリやPlatform SDKreferent_typeってなってなかったか!?

というわけで再び調査。MS製のものはreferent_typeGCCFDISはmapped_typeになっている。興味深い事に新C++言語入門 シニア編(下) クラス機能http://www.wakhok.ac.jp/~sumi/stl/header/map.html#templateはどちらにも触れていない。

うーん、ヤッパリmapped_typeの方が正しいんだろうなぁ。とcppllのログを見つけた。これこれこれ。ヤッパリmapped_typeらしい。

こんの腐れMぇ……あれ?待てよ?

あー結局MSの規格無視か。やれやれ全く困ったもんだ……と思っていたが、ふと、『あれ?』と思った。

たしかMSのC++ライブラリは、かのP.J.Plauger氏の会社が作ってたんじゃなかったっけ?確かにヘッダファイルの下の方にCopyright (c) 1995 by P.J. Plauger. ALL RIGHTS RESERVED.との表記がある……あれ?あれれ??

ふと気づいて

さらに、ふとVisual C++ 2005 Express Editionのincludeフォルダを覗いて見ると……

あ、普通に標準ライブラリって入ってたのね…….NET関係(C++/CLI独自)のヘッダしかないものだとばっかり思ってた。

よく見たらちゃんと標準に合わせた形に修正されているし……

………………あー、うん。アレだ。
みんなPlatform SDKよりVC++2005のライブラリ先に読むように設定気をつけようぜ!!!
…………って事で。

いやマジすんませんMS&Plauger氏。

作ってみようと思った
勿論車輪の再開発は悪だというのは知っているので同じようなものが無いかwebで探してみたが、見つからなかった。最も、私の探し方が悪いだけかもしれないが。
FDIS
Final Draft International Standard。国際規格最終案。本当は『最終案』ではないちゃんとした国際規格(IS)を当たるべきなのかもしれないが有料なので……(^^;ゞ
C++のFDISならば、このページで閲覧する事が出来る。
P.J.Plauger氏
C MAGAZINEに掲載されていた同氏の記事(翻訳)には次のようにある。
title="C MAGAZINE 2006年3月号 14頁"> C/C++の標準規格に従ったライブラリを開発・販売するDinkumwareという会社を経営するかたわら、コンピュータプログラミング分野でのコンサルタントとしても活動している。また、C/C++の標準規格の作成にも携わっていて、アメリカ合衆国、ヨーロッパ、オーストラリアおよび日本での会議に招待されセミナーを行っている。
C++世界ではかなりの有名人だと思われる。
posted by 天井冴太 at 17:41| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2006年07月08日

LAMP学習つれづれ記 - 環境構築でハマッタ

学校経由でLAMPな開発環境を自習する機会が出てきた。興味が無いといったら嘘になる。最近web2.0、web2.0と賑やかだしね。

早速Apache 2.2.2とPHP 5.1.4とMySQL 5.0.22のWindows版を落としてくる。Linuxじゃ無い時点で既にLAMPとはいえないが、OSは日頃使う環境の方が何かと便利だろう。

それぞれ英語のページにインストーラにドキュメントにと、英語に苦しめられながら何とかインストール完了。

いきなりコケた

PHPの設定ファイルphp.iniはデフォルトで用意されているphp.ini-recommendedを利用して、Apacheのhttpd.confにPHP用の設定追加して~、と思ったら、Apacheが癇癪起こした。 Apache2.2 PHP5.1モジュール読込エラー ……んー?何でだ?タイプミスもなさそうなのに。

某ページで『apacheの-tオプションで設定ファイルの検証してくれる』というので早速やってみる。

C:\Program Files\Apache Software Foundation\Apache2.2\bin>httpd -t
httpd: Syntax error on line 493 of C:/Program Files/Apache Software Foundation/Apache2.2/conf/httpd.conf: Cannot load C:/php/php5apache2.dll into server: \x8ew\x92\xe8\x82\xb3\x82\xea\x82\xbd\x83\x82\x83W\x83\x85\x81[\x83\x8b\x82\xaa\x8c\xa9\x82\xc2\x82\xa9\x82\xe8\x82\xdc\x82\xb9\x82\xf1\x81B

なにこれー。php5apache2.dllモジュール読み込みが拙いのは判ったが後半の記号の列は何?

ググッて見たら曰く、『php5apache2.dllはapache2.0用の。2.2じゃ動かんよー』との事……(゚д゚)
解決法としては……

  1. PHPのsnapshotからphp5apache2_2.dll引っ張ってくる (らびあんろーず - 今日の出来事。)
  2. Apache2.2用のphp5apache2.dllを落としてくる。(あらきけいすけの雑記帳 - インストール関連メモ(WindowsXP/Apache2.2.2/PHP5.1.4/MySQL5.0.22))

……の2種類があるらしい。どちらにしようか迷ったが、後者を選んでみた。
………………ん、解決。

……………………あー、うん、いいんだけどね。解決したから。
最初英語読み間違えたかと思って何度も読み返してたんですけど。それで2日ぐらい棒に振ったんですけど。頼むからせめてドキュメントに書いといて……

自習
まぁ正確には学校でもやってるんだけど。それにプラスして、という意味。
Linuxじゃ無い時点で既にLAMPとはいえない
んー……………………WAMP??
ラベル:Apache PHP
posted by 天井冴太 at 23:00| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2006年03月09日

C++のループ変数に引っ掛かった話

C++ではループ中のみ使う変数を定義する事が出来る。例えば次の通り。


// 此処ではiにアクセス出来ない
for(int i = 0; i < 10; i++) {	// ループ内のみで使うint型変数i
	std::cout << i << '\n';	// iにアクセス出来る
}
// 此処ではiにアクセス出来ない

更に、C/C++では複数の変数をループ時に初期化することも出来る。


int i;
float f;
for(i = 0, f = 1.2f; i ≶ 10; i++) {	// i, fを初期化
	std::cout << i << f << '\n';
}

意外と気づいてなかったが、この2つ、場合によっては併用出来ないようだ。

続きを読む
ラベル:C C++
posted by 天井冴太 at 23:56| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2006年02月15日

Win32 APIのCreateFileはバイナリでしか使えない

しばらくハマッタんでメモメモ。

DWORD writedByteNumber;

HANDLE file_ = CreateFile(_T("ファイル名"), GENERIC_WRITE, FILE_SHARE_READ,
    NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

WriteFile(file_, _T("ほげ\n"), (DWORD)_tcslen(_T("ほげ\n")),
    &writedByteNumber, NULL);
WriteFile(file_, _T("ふが"), (DWORD)_tcslen(_T("ふが")),
    &writedByteNumber, NULL);

こんな感じのコードでどうしても改行されない。出力先ファイル見てみると改行されている筈の場所に何やら半角の豆腐が1個在るんで、「あ、バイナリでの書き込みになってるな。」というのは判ったんだが、ヘルプ漁ってもwebで調べてみてもテキスト形式でファイル開く方法が全く見つからない。もしやと思って、WriteFileも調べてみたがダメ。

散々調べて分からなかったので、丁度その場にいた某bp師に質問。

天井冴太Win32 APICreateFile()でテキストファイル開くのはどうするんですか?
某bp師出来るわけ無いじゃん。むしろ出来るならこっちが知りたい。

しょうがないので書き込む文字列の\n\r\nに書き直す。取り合えず改行するようにはなったが、何か釈然としない……。

Cのfopen()、C++のstd::fstream系のノリでは使えないのか……
必死になって調べた時間返せヽ(`Д´)ノウワァァン!!

ラベル:Win32_API
posted by 天井冴太 at 16:53| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2005年11月03日

&quot;_&quot; アンダースコアに気をつけろ!!

どうも彼方此方で目にするサンプルコードの『間違い』が気になって仕方ない。我が専門学校で教師の方々のコードでさえ或る『間違い』を犯してしまっている。その『間違い』が顔を出すのは大体にしてインクルードガードの部分なのだが。

#ifndef _INCLUDE_GUARD
#define _INCLUDE_GUARD

// 色々コード

#endif

とか、

#ifndef __INCLUDE_GUARD__
#define __INCLUDE_GUARD__

// 色々コード

#endif

……なんて感じに書いてある。

頭に"_"の付く名前複数の"_"が何処かに付く名前C/C++の規格的には予約されているのである。が、意外と知られていないのだろうか?

恐らく、XPのコーディング規約でもJava版はメンバ変数(Java風に言えばフィールドか)の頭に"_"を付けるようになっているが、C++版では名前の末尾に"_"を付けるようになっているのもこの所為だろう。

……まぁ、とりあえずそれで問題が起きた、という話は聞かないが、後々呪いが掛かった時に泣いても誰も助けてくれない事を考えると注意しておくべきだ、と思うのだが、どうだろう?

ラベル:C C++
posted by 天井冴太 at 21:35| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2005年10月09日

sizeofが0にならない?

ネタがない。第1回目の記事を書いてからもうどれだけ経った事か。いい加減なんか書かないと。
……て言うか、前回みたいなhackモノってそうそう在る訳無いじゃないか。何考えてるんだろう。俺。 ……という訳で、今日は小ネタを。

さてさて、C/C++で型のサイズを求めるときに使う演算子sizeof

sizeof(int) == 4sizeof(double) == 8C/C++環境で、

struct S {
    int i;
    double f;
};

……という構造体を作ると、この構造体Sのサイズはsizeof(int) + sizeof(double)12となる。

ココまでは当たり前の話。では、

struct Nothing {
    /* あ!メンバが居ない!! */
};

……なんてメンバの無い――空の構造体をC++で作ったらどうだろうか?

普通に考えるならば、sizeof(Nothing) == 0だろう。しかし、実はそうはならない。

std::cout << sizeof(Nothing) << "\n"; 1

ご覧の通り、sizeof(Nothing) != 0である。

実はこれはC++規格できちんと決まっているらしい。いかに空構造体のオブジェクトといえど、存在する以上はサイズがある、と。

Nothing array[10];
Nothing *p1 = &array[3];
Nothing *p2 = &array[8];

……だったりすると、別要素を指している筈のp1p2p1 == p2になって変だと云う事らしい。

……あ、ココまで書いて気がついたけど、次のコードの場合sizeof == 0だと動作が変わってしまう。

void f(Nothing n) { cout << "called f()" << "\n"; }

int main()
{
    const int size = 10;
    Nothing array[size];

    for(Nothing *p = array; p < array + size; p++) {
        f(*p);
    }
}

sizeof(Nothing) != 0だと、f()が期待通りに10回呼び出されるが、sizeof(Nothing) == 0だと、1回も呼び出されなくなるforループに入ったとたんにループ条件p < array + sizeが偽となる為だ。

という事はsizeof(Nothing) == 0を許すと、STLのアルゴリズム関係がsizeofの結果によって挙動が変わってきてしまう事になる。(気づいただろうか、上記コードのforブロック部分はstd::for_each(array, array + size, f)の展開だ。)

……とまぁ、そんな訳で、空の構造体でもサイズがあると云う事になっているのだろう。いや、言語の裏に隠れる意図を考えるのはなかなか面白い。

もっとも、そもそも『空の構造体』なんてモノを書く機会なんてなかなか無いだろうし、仮に書いたとしても、上みたいな使い方はしないだろうが。いくらなんでも。

参考

C/C++環境
周知だとは思うが、それぞれの型のサイズは厳密に定められていない(実装依存)。今回挙げた型サイズはMirosoft Visual C++ 6.0に依った。
因みに(面倒なので)アライメントは考えていない。
構造体
記事中では構造体(struct)と表現しているが、これは共用体でもクラスでも一緒である。
sizeof(Nothing) != 0
今回使ったVC++ 6.0では1となったが、Borland C++ Compiler 5.5では8となるらしい。

因みに今回の話、当てはまるのはC++だけのようだ。Cだとコンパイラに怒られた。(VC++ 6.0で確認)

ラベル:C C++
posted by 天井冴太 at 23:22| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は90日以上新しい記事の投稿がないブログに表示されております。