SyntaxHighlighter

StackEdit CSS

2013年4月15日月曜日

C++で遠隔操作

釣り。

授業を聞いててふと思いついた。
その授業では、モジュールの隠ぺい(オブジェクトのprivateとか)について説明していたんだけど、C++ではprivateにしても外からいじれるという話をどこかで聞いたので試したくなった。

そのオブジェクト自身が漏らす場合

class Player {
    int money;
public:
    Player(int m) : money(m) { }

    int getMoney() { return money; }

    int* wrongMethod() { return &money; }
};

int main(){
    Player player(10);

    cout << player.getMoney() << endl; //=> 10

    int* money = player.wrongMethod();
    *money *= 100;
    cout << player.getMoney() << endl; //=> 1000

    return 0;
}
何かのミスで、privateのメンバ変数のアドレスを漏らしてしまった場合。これはほかの言語でもありうるだろう

外から位置を特定して触る方法

class Player {
public:
    int power;
private:
    int HP;
    int MP;
    int money;
public:
    Player(int m) : money(m) {
        cout << &power << endl;
        cout << &HP << endl;
        cout << &MP << endl;
        cout << &money << endl;
    }

    int getMoney() { return money; }
};

int main(){
    Player player(10);
    cout << &player << endl;

    cout << player.getMoney() << endl; //=> 10

    int* money = (int*)&player + 3;
    *money *= 100;
    cout << player.getMoney() << endl; //=> 1000

    return 0;
}
Playerのコンストラクタでメンバのアドレスを調べたら、playerのアドレスがpowerと一致していて、また、power、HP、MP、moneyの順でアドレスが4(=sizeof(int))ずつ増えていったのでもしやと思い、playerのアドレスに+3したら見事にアクセスできたw
C++のポインタが理解しにくいといわれてるのは、クラスなどの先進的な機能とポインタなどのプリミティブな機能が同居しているところにあるってどっかで見たけど、まさにその通りだとこれで実感した。こういうキケンなことができることは、速度とのトレードオフだろうけど。

おまけ

privateメソッドは内部から漏れることぐらいしか思いつかなかった
class Player {
    void privateMethod(){
        cout << "@privateMethod" << endl;
    }
public:
    void (Player::*wrongMethod())() { return &Player::privateMethod; }
};

int main(){
    Player player;
    (player.*(player.wrongMethod()))();

    return 0;
}
関数ポインタの書き方わからんwww

2013年4月11日木曜日

CoffeeScript + enchant.jsでパズドラもどきを作ってみた感想

動機

パズドラ面白そうだなぁ → ソシャゲーはちょっとなぁ。。。 → じゃあつくってみるか

スクショ


どう見てもパズル&ドラゴンズです。本当にありがとうございました。

感想

CoffeeScriptとenchant.js、どちらも初めてだったが、意外とすんなりできた。バグを直す時間のほうが長かったんじゃないかってくらい。CoffeeScriptはRubyがまぁまぁ使えるので、直ぐに書けるようになったし、enchant.jsは情報が多かったのでそれほど詰まるってことはなかった。
 JavaScriptはよくわからないので比べられないが、少なくともCoffeeScriptで実装中のストレスはほとんどなかった。0引数の関数を呼ぶときのかっこをRubyのノリで付け忘れてすこし悩んだり、インデントを間違えて数時間悩んだりしたぐらい。豊富なシンタックスシュガーのおかげでサクサクかけた気がする。->が結構かっこいい。
isInField = (x, y) ->
    #...
とか。
lines.forEach (line) ->
    #...
はRubyでいうブロックみたいに見える
 enchant.jsはSpriteで画像を表現するのに少し慣れなかった。勝手にカウントしてくれるラベルがあったのは少し驚いた。こうしたもののおかげで実装の負担が軽くなるのはいいことだと思う。何より好感が持てたのは、ゲームに使える画像がいくらか付属していることだ。ゲームを作っても絵が描けないので、見た目が残念だったりして、結構萎える。クオリティの高い画像が付属していると、作る側のモチベーションも上がるよなぁと思った。自分もドラゴンの画像を使わせてもらった。
 最初は充実感があったが、だんだん完成に近づくにつれ、充実感が無くなってきた。どれだけ頑張っても、本家には勝てない気がしてきたからだ(あたりまえ)。つまり劣化コピーだ。やはり模倣は面白くないなと身に染みてわかった。コピーしようと思ったらそれを超えるものを作らないと成長しないしね。
 ちなみに動機は実装している間に消えてしまったwww

2013年3月26日火曜日

return関数実装したった

もうなんかありそうなネタ。
思い立ったので、return関数をC++のインラインアセンブリを使って実装してみた。


#include <stdio.h>

void _return(){
    __asm{
        pop ebp //フレームポインタ回収
        pop ebp //_returnから脱出
        pop ebp //呼び出し元のフレームポインタ回収
        ret
    }
}

void _return(int val){
    __asm{
        mov eax, dword ptr [ebp + 8] //返り値セット
        pop ebp
        pop ebp
        add esp, 4 //呼び出し側の仕事
        pop ebp
        ret
    }
}

void func1(){
    _return();
    puts("ここは実行されない");
    return;
}

int func2(){
    _return(10);
    puts("ここは実行されない");
    return -1;
}

int main(){
    
    func1();
    
    printf("%d\n", func2()); //=> 10
    
    return 0;
}

実装してから思ったが誰得だwww

2013年2月23日土曜日

OnlineJudge自作2

 前のやつの日付を見たら、もう2か月以上も前だった…
 一応ショートコーディング大会当日までに実装は間に合ったんだが、エラーは出るわ、ランキングに反映されないわ、ソースを送っても無視されるブラウザ(Firef○x)があるわでうまく動かなかった。


終わりの始まり

 当日2週間前。1週間前から始めればおk!と、余裕をこいて実装をはじめなかった。
 当日1週間前。そろそろはじめないとやヴぁいと思い実装開始。だが最初で最後の土日(当日は土曜日)を環境のセットアップでつぶしてしまう。
 土曜日は、流行のRuby on Railsを使おうと思い環境を入れ、実装をしているうちに、方法に慣れなかったのか思うように実装できなかったので、時間もないしこれは捨てたほうがいいのではと思い、Ruby on Railsの使用を中止し、PHPとPerlを使うことにした。
 日曜日は、さぁ環境を作ろうずと思い、Apacheをいれるも、なかなか思うように設定できず、1日つぶしてしまった。

最後の希望

 残り1週間。このあたりの記憶はあまりないが、毎日1~3時まで実装してた気がする。特に前日の金曜日は睡魔がやヴぁかった。

ぼくらのサーバー

 当日。朝起きたら、実装途中のPCがあった。急いで実装し、学校にいき、さぁテストしようと思ったら動かない。サーバーのスペースは友人に貸してもらったのだが、当方の環境と違ったのだ。GoogleTalkで友人と連絡を取りながら、何とか修正したが、(冒頭へ)


反省点

一番大きいのは、計画不足だ。ってあれこれ前もあったぞ。完成してから、アナウンスすべきだった。
マルチタスク慣れてないくせに、やりたいと思ったらすぐはじめてしまったのも裏目に出た。
まぁ経験になったからいいや。
今度から気を付けます。

2013年1月30日水曜日

C++のヘッダをUmletのプロパティに変換する

学校の課題で、クラス図を書く用があったのが、もうソースコードは書き終わっていて、ヘッダから書き移すのもアレだったので、変換プログラムを書いた。perlで書きたかったんだけど、windowsで環境が入ってなかったので、JScriptで。あと、正しいソース前提。

function join(c){
    var ret = new Array();
    for(var i = 1;i < arguments.length;i++){
        ret.push(arguments[i]);
    }
    return ret.join(c);
}

var args = WScript.Arguments;

if(args.length < 1){
    WScript.Echo("Error!");
    WScript.Quit();
}

var FS = new ActiveXObject("Scripting.FileSystemObject");

//  オープンモード
var FORREADING      = 1;    // 読み取り専用
var FORWRITING      = 2;    // 書き込み専用
var FORAPPENDING    = 8;    // 追加書き込み

//  開くファイルの形式
var TRISTATE_TRUE       = -1;   // Unicode
var TRISTATE_FALSE      =  0;   // ASCII
var TRISTATE_USEDEFAULT = -2;   // システムデフォルト

for(var arg_index = 0;arg_index < args.length;arg_index++){
    var fname = args(arg_index);
    
    var infile = FS.OpenTextFile(fname, FORREADING, false, TRISTATE_FALSE);
    
    var outfile = FS.OpenTextFile(fname + "_out.txt", FORWRITING, true, TRISTATE_FALSE);
    
    var visibility = "-";
    
    var classname = "";
    var fields = new Array();
    var methods = new Array();
    
    while(!infile.AtEndOfStream){
        
        var line = infile.ReadLine();
        
        var fixes = {"virtual " : "/", "static " : "_", "" : ""};
        
        var tokens;
        if(tokens = line.match(/class (\w+)/)){
            classname = tokens[1];
        }
        //private
        else if(line.indexOf("private:") != -1){
            visibility = "-";
        }
        //public
        else if(line.indexOf("public:") != -1){
            visibility = "+";
        }
        //protected
        else if(line.indexOf("protected:") != -1){
            visibility = "#";
        }
        //method
        else if(tokens = line.match(/(virtual |static |)(\w+) (\w+)\(([\w, ]*)\);/)){
            
            var fix = fixes[tokens[1]];
            
            var ret_type = tokens[2];
            
            var name = tokens[3];
            
            var arg = tokens[4].replace(/(\w+) (\w+)/g, function($1, $2, $3){ return $3 + " : " + $2; });
            
            var s = join(" ", fix, visibility, name + "(" + arg + ")", ":", ret_type, fix);
            methods.push(s);
        }
        //field
        else if(tokens = line.match(/(|static |)(\w+) (\w+);/)){
            
            var fix = fixes[tokens[1]];
            
            var type = tokens[2];
            
            var name = tokens[3];
            
            var s = join(" ", fix, visibility, name, ":", type, fix);
            fields.push(s);
        }
        else{
            //WScript.Echo("no matches");
        }
        
    }
    
    outfile.WriteLine(classname);
    if(fields.length > 0) outfile.WriteLine("--");
    for(var i = 0;i < fields.length;i++) outfile.WriteLine(fields[i]);
    if(methods.length > 0) outfile.WriteLine("--");
    for(var i = 0;i < methods.length;i++) outfile.WriteLine(methods[i]);
    
    infile.Close();
    infile = null;
    
    outfile.Close();
    outfile = null;

}

WScript.Echo("finish");

手で書き写した方が速いとわかってたがプログラムの練習のために…
他の人も使ってくれるみたいだし。

2013年1月19日土曜日

個人的メモ

ruby-opengl導入(Windows)

http://www.libgosu.org/cgi-bin/mwf/topic_show.pl?tid=278 の下から2番目のレスにあるgemファイルをダウンロード
gem install [ダウンロードしたgemファイル]


gem installが失敗する件(failed to build native extension)

...
checking for hoge.h ... no
...

のhoge.hを持つライブラリを探し、インストール ...
そこからどうする?わからん


C++

copy constructor と operator=は親クラスのメソッドが継承されない



VirtualBoxでネット接続できない

routeでdefault gatewayを確認し、NATのほうになっているか確認
参考 http://d.hatena.ne.jp/Yudoufu/20100117/1263677767

2012年12月22日土曜日

Windows7の付箋のデータを取得

普段使ってるWindows7の付箋のデータをバックアップしたくなったので、Win32APIを使って組んでみた。


#include<iostream>
#include<windows.h>

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lp){
    TCHAR name[1024];
    GetClassName(hwnd, name, 1024);
    if(lstrcmp(name, "Sticky_Notes_Note_Window") == 0){
        HWND child;
        child = FindWindowEx(hwnd, NULL, "DirectUIHWND", NULL);
        if(!child) return TRUE;
        child = FindWindowEx(child, NULL, "CtrlNotifySink", NULL);
        if(!child) return TRUE;
        child = FindWindowEx(child, NULL, NULL, NULL);
        if(!child) return TRUE;
        
        TCHAR text[1024];
        SendMessage(child, WM_GETTEXT, 1024, (LPARAM)text);
        std::cout << text << std::endl << std::endl;
    }
    return TRUE;
}

int main(){
    EnumWindows(EnumWindowsProc, 0);
    
    return 0;
}

 Spy++を使って付箋を見たら、"Sticky_Notes_Note_Window" - "DirectUIHWND" - "CtrlNotifySink" - ""のクラス名の順に子になっていた。一番下に、目的のデータがあるということが分かった。 
 目的のデータがあるハンドルを取得して、よしデータを取得しようと思って、17行目に
GetWindowText(child, text, 1024);
と書いたらtextには何も入っていなかった。MSDNをよく見たら、
他のアプリケーションのエディットコントロールのテキストをこの関数で取得することはできません。
とあった。知らなかったorz.. 下にあった、
他のプロセス内のコントロールのテキストを取得するには、GetWindowText 関数を呼び出すのではなく、直接 WM_GETTEXT メッセージを送ります。
の通りにしたら動いた。 やったね!
参考
MSDN GetWindowText