宙ぶらりんの一日

朝とともに私の宙ぶらりんの一日は始まる。

始まる、と言っても、何も起こりはしない。洒落にもならないが、身体もベッドから起こさない。スコップで胸の肉を背中まで抉り取られたような痛みの存在を再確認して、上半身を起こすことが出来ず、また眠りにつく。眠れない日は、仕方なくスマホを見ている。人気のツイートや、まとめサイトはてなのホットエントリだとか、くだらない。心底くだらないと思いながらそれを「食べて」気を紛らわす。刹那的な情報の消費は痛みから瞬間的に目を逸らさせてくれるという効用以外、私のもとにいかなる意味のある経験ももたらしはしないけれど、私は早く時間が経ってほしいと願いながら、そんな非生産的なことに時間を費やすしかない。

十一時になる。身体を持ち上げては痛みのために断念することを三回ほど繰り返して、ようやく髭を剃ることができた。 以前は鏡を見るたびに不格好に膨らんだ自分の姿に嫌悪感を覚えていたものだが、最近はすっかり慣れてしまった。

相も変わらず胸を貫くずっしりとした、しかし目に見えない太い杭の、その圧力を騙しながら家を出た。

駅へ着くと、私はそばのパン屋へまっすぐ入っていった。理由はこの上なくシンプルで、朝から何も食べていなかったのだ。 なぜ朝から何も食べていないのかといえば、痛く、ただ痛く、ものを喉に流し込むことが億劫になるほど痛かったのだ。それが昼になってようやく、食欲がかろうじて上回る。夕方まで何も食べない日も多い。

ところがいざ食べる段になると、滑稽なことに、私は甘い菓子パンや、ドーナツ、そのほか砂糖の塊を混ぜ物で嵩増ししたような、そんなものばかり食べる。馬鹿げている。しかし朝起きてから痛みに苛まれ続けていると、溜まったストレスに身体が悲鳴を上げて、砂糖か油を摂れ、今すぐに摂れ、と叫び出すのだ。これでは太るのも当たり前だ。

私は店を出てすぐ包装を開け、歩きながら今買ったパンを食べたり、酷いときは電車の中でものを食べる。もう私には外からどう見られているかを気にかける余裕なんてものは、ストレスに圧迫されてどこかへ逃げ去ってしまった。そうして残ったものは、ぶよぶよの身体で、公衆の面前でみっともなく菓子を食い散らかす醜い人間だ。

そしてこの上なくおもしろいことに、そうした行為も一切私のあの痛み、心臓を無理やり引きちぎられたようなあの痛みを和らげることはないのだ。そして身体の抵抗し難いストレス信号が消えた代わりに、私の中に自己嫌悪と脂肪が置いていかれ、積み重なっていく。

電車の中ではまたスマホを見て、早く駅に着いてくれと願いながら痛みをやり過ごす。と書いても、ここで1時間ほど耐えねばならない。すると見るものがなくなってくる。けれど気を紛らわすために、同じサイトを延々と巡回したりする。空しい。

東大前に着くと、情報科学科の建物である理学部7号館まで七八分歩かねばならない。私は歩行中もスマホの画面に流れていく情報を必死で咀嚼して、痛みの中で歩くという行為から心を逃がそうとする。みっともない自分がまた嫌いになる。

建物へ着き、学生控室に入ってソファに寝転んだところで、ようやく私は少しほっとする――横になる方がいくらか休まるので、このソファの存在はとてもありがたい。 私は寝転がりながらPCを操作して、ただ検索して出てきた資料と照らし合わせて表を埋めるだけの課題をやった。これで全7回の課題はすべて提出したが、本当に単位が来るのだろうか。なにしろ講義は全く聞いていないのだから。 最近はPCの操作もずっと寝転がってやっている。とにかく身体を起こしているのがつらい――キーボードはとても打ちづらいが。

学生支援室にて週に一度のカウンセリング。担当者は一度変わったが、もう2年間も続けている。このために痛みを我慢して大学へ来た。臨床心理士のUさんはこちらの話にじっと耳を傾けてくれるので、彼と話している間はいくらか落ち着ける。が、やはり胸はずきずきと痛む。 痛みが再発した原因は分からず、進展がないまま部屋を後にする。また学生控室に戻り、別の講義の課題をやる。

学科長の教授と面談した。前回から痛みについての進展がないので、お互い黙ってしまう。結局休んで様子を見るという結論になる。先生が悪いわけではないが、痛みに対して学科ができることは何もないのだ。

同じようにスマホを見ながら東大前まで歩き、スマホを見ながら電車に乗り、スマホを見ながらバスに乗り、バス停から家までの3分ほどの道でも結局歩きスマホで帰宅した。

ベッドに倒れこむ。片道1時間半の間身体を縦にするだけでこんなにも辛いということが悲しいが、けれど慣れてしまった。

朝と同じようにスマホで気を紛らわし、親が用意してくれた夕食を食べ、医者から出された効果の見えない薬を飲み、電気を消した。

明日こそは痛みがなくなってくれないものか。そう思いながら、痛みに顔をしかめてベッドに入る。

けれど、そんな変化が突然訪れることはないと、私は知っている。

Rubyでコードゴルフ ~235bytes → 40bytesの過程を追う~

TL;DR

コードゴルフとは? その魅力は? の解説と、Rubyで書かれた普通(?)のコードがワンステップずつ縮んでいき、コードゴルフらしいコードになるまでの解説。

目次

  • まえがき
  • コードゴルフとは
  • 今回のお題
  • 普通のRubyコード
  • ステップごとの解説
  • おわりに

まえがき

コードゴルフとは、与えられたお題でどれだけコード長を縮められるか? を競う遊びです。

所属するサークルTSGの学祭(五月祭)企画でミニ・コードゴルフ大会というものを開催することになり、その実況担当になりました。→参加者のuraさんがWriteupをUPしてくれました:TSG LIVE! 3 ライブコードゴルフ大会 writeup - 何か書く

私はコードゴルフという遊びについて全く触れたことがなかったのですが、今回の企画のためにRubyでコードを(主に部員のみんなの助けにより)縮め、コードゴルフの一端を体験しました。せっかく説明用のスライドも作ったので、共有したいと思います。

なお、筆者はそもそもRubyを書くのすら初めてでした。Rubyistから見ると不思議な点が多々あると思います。間違いなどあれば指摘していただけると幸いです。

コードゴルフとは

先ほども書いたのですが、「与えられたお題でどれだけコード長を縮められるか(バイト数を減らせるか)」を競う遊びです。 基本的に、お題はかなり簡単なものが与えられます。Atcoder Beginner ContestのA問題をちょっと難しくしたくらいだと感じました。なので簡単に書けるのですが、そのコードをいかに縮められるか、というところで様々な知識が要求されます。

当然のことながら、「それの何が面白いの?」という疑問が出てくると思います。今回私が感じたのは以下の3点です。

  • 一見すると意味不明なコードがちゃんと動く

ゴルフコードは改行・空白等が基本的にない上、コード長を短くするために様々な工夫が施されています。ですから、一見しても(コードゴルフに慣れていなければ)何が何だかわかりません。でもちゃんと動くのです。そこにちょっと感動し、ああそういうことか! と仕組みが分かるとちょっとうれしくなれます。

  • コードを縮めるために細かい言語仕様が役に立つ

普段のコーディングではある処理に対しては私個人のやり方をひとつ覚えてさえいればどうにかなるため、複数の書き方を覚える必要に迫られません(もっとも、これは私が仕事として書いていないせいかもしれませんが)。

ですが、コードゴルフでは複数の書き方、すなわちより短くなる書き換え方を知っていることが強みになります。それは結局言語の仕様についての知識に直結し、深い知識によるコード短縮テクに「こんな書き換え方があったのか! 賢い!」と唸らされます。

世の中には「出来上がったコードが星空のように見える言語」や「絵文字でプログラミングする言語」、「人間にとって読みにくいコードを生成する言語」などのように、様々な非実用的な言語が存在します。

それらはある種のジョークや実験的言語として作られたもので、実用的でないので当然使われないわけですが、コードゴルフという遊びにおいてはこの難解プログラミング言語(esoteric programming language, esolang)によるプログラミングが普通のプログラミングにはない面白味を与えてくれます。しかし、この記事はRubyでのコードゴルフが主題なのでesolangには触れません。

今回のお題

f:id:Szkieletor:20190519181526p:plain

  • 上の画像のように、アルファベットと数字が(ほぼ)交互に並んだ文字列が与えられます。
  • 数字の数だけ直前のアルファベットを連続させた文字列を返してください。

というものです。

これは「連長圧縮」という技術をテーマにしており、実際にファクシミリで使われていた(使われている?)圧縮方法らしいです。

これだけだとあまりにも問題が簡単なので、制約が加わっています。

  • 連続回数が1回のときは、数字は省略される。

つまり、sssgwwに対応するのはs3g1w2ではなく、s3gw2になる、ということです。この制約により、前から2文字ずつ読んでいくやり方は不可能になります。

この制約をクリアする方針の一つが以下になります。

f:id:Szkieletor:20190519182542p:plain

今回はこの方針に基づいて実装したコードを縮めていきます。

普通のRubyコード

cipherText = gets
number = "23456789"

for i in 0..(cipherText.length - 1) do
    if number.index(cipherText[i]) == nil then
        print cipherText[i]
    else
        for j in 0..(cipherText[i].to_i - 2) do
            print cipherText[i - 1];
        end
    end
end

筆者はこのコードが初Rubyなので、まったくRubyらしいコードになっていないと思います。Rubyはふつうforを使わない、と聞いてびっくりしました。聞きかじっただけなので嘘を言っているかもしれませんが。

補足すると、変数numberに入力文字が数字かどうか判定するための文字列を格納し、indexで検索することで処理を分けています。

現在のコード長が235bytesなのですが、最終的に40bytesまで縮みました。そのコードがこちら。

$<.chars{|d|n=d.to_i-1;puts n<0?B=d:B*n}

ちなみに、解説のkurgmさんとプレイヤーのuraさんがちょっとずつ違う方法で36bytesまで縮めていました。Twitterでも「36が最短」というツイートを見つけたので多分これが一番短いと思います。

さて、ではコードを縮めていきます。

ステップごとの解説

最初の方は当たり前のことを書いているので飛ばしてもよさそうです。ちなみに書いている本人はどこまでがRubyistにとっての常識なのか全くわかっていません。

1. 変数名を1文字にする

コードゴルフではコードの短さが命なので、変数名は1文字にしてしまいます。もちろん悪いプラクティスなわけですが。

171B(-62)

2. 空白・改行をなくす

コーディング規約にもよりますが、-==の両隣にはスペースを挿入することが好ましく、また適宜改行を挿入することがよいプラクティス、のはず。これも取り除きます。

158B(-13)

c=gets
n="23456789"
for i in 0..(c.length-1) do
    if n.index(c[i])==nil then
        print c[i]
    else
        for j in 0..(c[i].to_i-2) do
            print c[i-1];
        end
    end
end

3. 後半のforはいらない

テクでも何でもないです。 後半のforは「今読み込んだ数字-1回、インデックスが一つ前の文字を出力する」という処理ですが、そもそも'c' * timesctimes回連続させた文字列を作れます。これをprintした方が短いです。

133B(-25)

c=gets
n="23456789"
for i in 0..(c.length-1) do
    if n.index(c[i])==nil then
        print c[i]
    else
        print c[i-1]*(c[i].to_i-1)
    end

準備:foreachに置き換え

Rubyにおけるforは特殊なので、do...end{}などができません。ということでeachに書き換えます。

c=gets
n="23456789"
(0..c.length-1).each do |i|
    if n.index(c[i])==nil then
        print c[i]
    else
        print c[i-1]*(c[i].to_i-1)
    end
end

4. (0..c.length-1).each を書き換え

入力として受け取った文字列の長さだけループを回していますが、これはc.length.timesというメソッドと同じです。 さらにlengthメソッドと同じ機能を果たすsizeメソッドがあり、こちらの方が文字数が短いです。

125B(-8)

c=gets
n="23456789"
c.size.times do |i|
    if n.index(c[i])==nil then
        print c[i]
    else
        print c[i-1]*(c[i].to_i-1)
    end
end

5. do...end

size.timesメソッドのdo...end{}で置き換えられます

変わっている部分がわずかなのでコードは次にまとめます。

120B(-5)

6. ifを条件演算子

条件演算子とはa ? b : cという書き方のことで、aがtrueならbが、falseならcが実行されます。ということで、ifを置き換えます。

この辺りから、表示されるコードには見やすさのために改行を入れています。

103B(-17)

c=gets
n="23456789"
c.size.times{|i|
    (n.index(c[i])==nil)?(print c[i]):(print c[i-1]*(c[i].to_i-1))
}

7. printはまとめられる

a ? print b : print cprint (a ? b : c) と書き換えられます。

97B(-6)

c=gets
n="23456789"
c.size.times{|i|
    print (n.index(c[i])==nil)?(c[i]):(c[i-1]*(c[i].to_i-1))
}

8. n.index(c[i]==nil)

(x == nil) ? b : cx ? b : c と書き換えられます。実はx = false となると結果が違ってしまいますが、今回のケースではindexメソッドが返すのは数値かnilなので、大丈夫です。

さらに、n.index(c[i])n[c[i]]と書き換えられます。xに(文字列型としての)数字が入っていればn[x]n.index(x)と同じ働きをします。たとえば、n['2'] = '2' となり、n['t']のように存在しない文字の場合はnilを返します。

78B(-19)

c=gets
n="23456789"
c.size.times{|i|
    print(n[c[i]]?c[i-1]*(c[i].to_i-1):c[i])}

準備:i-1をくくりだす

現状size.times{|i|}の中で配列のインデックスとしてiが使われている箇所の中に、1か所だけi-1が使われています。これを別の変数としてくくりだすことで別のメソッドに置き換えができ、さらなる短縮が可能になります。

86B(+8)

c=gets
n="23456789"
b=nil
c.size.times{|i|
    print(n[c[i]]?b*(c[i].to_i-1):c[i])
    b=c[i]}

9. size.timesc[i]の置き換え

先ほどの準備により、size.times{|i|chars{|d|に、c[i]dに置き換えられます。

69B(-17)

c=gets
n="23456789"
b=nil
c.chars{|d|
    print(n[d]?b*(d.to_i-1):d)
    b=d}

10. b=nil

rubyの変数は初期化なしで宣言すると初期値がnilになります。この際大文字で宣言してスコープをグローバルにしないといけません。小文字のローカル変数だとループの中で2回目以降参照できなくなってしまいます。

ちなみに大文字の宣言はグローバル定数なので再代入はwarningが出ますが、warningだけなので無視します

63B(-6)

c=gets
n="23456789"
c.chars{|d|
    print(n[d]?B*(d.to_i-1):d)
    B=d}

11. printputs

改行が入るかどうかが違います。今回はルール上改行が無視されるので置き換えられ、1バイト短くなります。コードは次にまとめます。

62B(-1)

12. nを消す

数字かどうか判定するためにnを用意していましたが、実はn=d.to_i - 1とすると、d=nild.to_i = 0d.to_i - 1 = -1となるので、n<0trueならアルファベット、falseなら数字と判定できます。

47B(-15)

c=gets
c.chars{|d|
    n=d.to_i-1
    puts n<0?B=d:B*n}

13. cを消す

入力のために変数を用意する必要はなく、$<でOKです。

$<.chars{|d|
    n=d.to_i-1
    puts n<0?B=d:B*n}

最後に、見やすさのために挿入していた改行を取り除きます。

$<.chars{|d|n=d.to_i-1;puts n<0?B=d:B*n}

完成です。40バイトになりました。

ちなみに最短である36バイトのコードでは、gsubメソッドを使います。

おわりに

当然私はRubyを何もわかっていないので、上の短縮はTSG部員のみんなにSlackで訊ねた結果を載せています。強い人がすぐそばにいるって素晴らしい。教えてくれた@kcz, @hakatashi, @kurgmさんに感謝です。

コードゴルフ場(?)というか、コードゴルフが楽しめるサイトとして anarchy golf があります。

コードゴルフ大会はライブ企画でしたが、YouTubeでストリーミング視聴できます。実況できていませせんが……(画面を追えていない)。2日目にもコードゴルフ大会があり、そちらはちゃんとプレイヤーの画面を追ってくれていました。

スライドも作ったのでリンクを載せておきます。

面白いesolangが多かったので、その紹介記事も余裕があれば書きたいです。

Szkieletor( @gh_end_)

オペレーティングシステムの仕組み memo

オペレーティングシステムについてもう少しちゃんとやりたいという欲求があり、適当に”Operating system begginner"とググった。そこでOSdev(https://wiki.osdev.org/Main_Page)へ辿り着き、全く私のレベルに沿っていない内容に打ちのめされ、とりあえず別のものを探した。

そこで行き着いたのがこのリンク。

dev.to

そして紹介されていたものがこの本(埋め込もうとするとアフィリエイトになってしまう仕様っぽい。やめたい)。

オペレーティングシステムの仕組み (情報科学こんせぷつ)

オペレーティングシステムの仕組み (情報科学こんせぷつ)

自宅最寄りの図書館にあったのでさっそく借りて読んでみている。

#レベル

各論は細部まで深追いせず、分量が多くならないようにされています。 また逆に、浅すぎて事実の羅列になったりせず、仕組みを理解できるくらいには具体的に書かれています。

この紹介文通り、細かすぎず浅すぎず、それでいてOSの機能についてしっかりと理解できる良い本だと思う。

ただし、ある程度の前提知識が必要。ハードウェアの領域にいくらか踏み込んで話すのと、コーディング用語、open()みたいなシステムコールの名前などが出てくるため、非情報系の人がいきなり読むのにはきついだろう。

ISerに関して言うなら、「計算機構成論」「オペレーティングシステム」さらに「システムプログラミング実験(の前半)」をやった後(つまり3S後の夏休みとか)に読むと、OSに対してよりしっかりとした理解が身につく。私は3Sの途中でリタイアして休学中なわけだが、幸い計算機構成論とオペレーティングシステムは単位を取れるくらいには全体像を理解できていて、あとシステムコールもシスプロで触ってはいたので運が良かった。

OSは深いところでハードウェアとも関わっているが、「オペレーティングシステム」の講義ではハードウェアの領域まで踏み込まないためにどうしても表面的な用語の解説で終わってしまったように思える。この本を読んでいくと、基本的には「あっ、この用語は『オペレーティングシステム』でやった」→(プロセッサやシステムコールなどにも踏み込みながらの解説)→「おお、よくわかる」という流れになる。まだ30ページぐらいしか読んでないけど。

メモ

なお、gdbなどのデバッガではソースコードとの対応を取りながらデバッグできるようになっている。これはシンボル情報を利用しているからである。デバッガを使うときは、機械語命令とソースコード上の位置を対応付けるため、通常よりもずっと多くのシンボル情報を必要とする。

シンボル情報(シンボルテーブル)の使われ方を理解していないためここがわからない。いまちょうどBinary Hacksの方でELFをやっているから、もしかしたらそこで分かるかもしれない。

誰か助けてください

stripコマンドで「unstrippedなコマンドからシンボル情報を取り除いて、ファイルサイズが小さくなるところを見てみよう」という箇所があり、unstrippedな例としてcatが挙げられている。ところが私のUbuntu 14.04 LTSではcatはstrippedなので、これを確認できない。一通り主要コマンドでfileしてみたが、すべてstrippedだった。

誰かunstrippedなコマンドを知っている方がいれば教えていただけるとありがたいです。

Binary Hacks Hack#5 ELF入門 memo

・オブジェクトファイルや実行ファイルはELF(Executable and Linking Format) というフォーマットで規定される。

・ELFフォーマットのファイルは、ELFヘッダテーブルが先頭にあり、プログラムヘッダテーブル・セクションヘッダテーブルがその後にある。

ELFフォーマットのプログラムの構造は下を参照。とてもわかりやすい。

ELF Format

まず、プログラムは複数の「セグメント」から成り、セグメントは複数の「セクション」から成る。

readelf -l 

するとプログラムヘッダを表示できる。各セグメントのタイプやアドレスなどの情報と、それぞれのセグメントがどのセクションを持っているかが表示される。

readelf -S

で各セクションのタイプ、アドレス、etc……の情報を表示できる。

ストリングテーブル

セクションのタイプの一つ。名前が格納されているテーブル。試しに

 $ od --skip-bytes 0x0001a5fc --read-bytes 0xfe -t x1z /bin/ls

すると、

0322774 00 2e 73 68 73 74 72 74 61 62 00 2e 69 6e 74 65  >..shstrtab..inte<
0323014 72 70 00 2e 6e 6f 74 65 2e 41 42 49 2d 74 61 67  >rp..note.ABI-tag<
0323034 00 2e 6e 6f 74 65 2e 67 6e 75 2e 62 75 69 6c 64  >..note.gnu.build<
0323054 2d 69 64 00 2e 67 6e 75 2e 68 61 73 68 00 2e 64  >-id..gnu.hash..d<
0323074 79 6e 73 79 6d 00 2e 64 79 6e 73 74 72 00 2e 67  >ynsym..dynstr..g<
0323114 6e 75 2e 76 65 72 73 69 6f 6e 00 2e 67 6e 75 2e  >nu.version..gnu.<
0323134 76 65 72 73 69 6f 6e 5f 72 00 2e 72 65 6c 61 2e  >version_r..rela.<
0323154 64 79 6e 00 2e 72 65 6c 61 2e 70 6c 74 00 2e 69  >dyn..rela.plt..i<
0323174 6e 69 74 00 2e 74 65 78 74 00 2e 66 69 6e 69 00  >nit..text..fini.<
0323214 2e 72 6f 64 61 74 61 00 2e 65 68 5f 66 72 61 6d  >.rodata..eh_fram<
0323234 65 5f 68 64 72 00 2e 65 68 5f 66 72 61 6d 65 00  >e_hdr..eh_frame.<
0323254 2e 69 6e 69 74 5f 61 72 72 61 79 00 2e 66 69 6e  >.init_array..fin<
0323274 69 5f 61 72 72 61 79 00 2e 6a 63 72 00 2e 64 79  >i_array..jcr..dy<
0323314 6e 61 6d 69 63 00 2e 67 6f 74 00 2e 67 6f 74 2e  >namic..got..got.<
0323334 70 6c 74 00 2e 64 61 74 61 00 2e 62 73 73 00 2e  >plt..data..bss..<
0323354 67 6e 75 5f 64 65 62 75 67 6c 69 6e 6b 00        >gnu_debuglink.<
0323372

と表示される。

改行のせいで非常にごちゃついているけれど、gnu.version とか gnu.version_rとか、そういう名前がこのテーブルに全て格納されていて、たぶん名前を使う際はこのテーブルへのアドレスで参照するのだと思われる。

ここまで(4/24)

調べたいこと

・ストリングテーブルの作られ方。プログラムに使用した変数名とかもここに格納されているという認識でいいんだろうか。そうなるとストリングテーブルの大きさは可変長なんだろうか。それとも十分な大きさのメモリを確保していて、うん千万という変数を作らない限り平気ということなんだろうか?

・e_shstrndxで指定されるセクションに名前が格納されている(e_shstrndxはELFヘッダのメンバ)。ところで、

readelf -S /bin/ls

すると、ストリングテーブルであることを指すタイプ=STRTABであるセクションが、e_shstrndxで指定された".shstrtab”の他にもう一つあるのが分かる。”.dynstr”というセクションだ。これは何のためのストリングテーブルなのか?

気になった記事

qiita.com

イエス or ノーの2択をつきつける質問に「ノー」と言いたい

心底くだらないことにエネルギーを浪費しているな、と自覚しながらこの記事を書いている。

おそらくほとんどの人には全くもってどうでもいいことだと思う(私だってどうでもいい)のだが、国会議員というとても立派な職業についている人たちが世の中には存在する。ごくごく少数の選ばれた日本人しかこの栄誉ある職に就くことはできず、そして会社員と違って任期があり、しかも衆議院議員の場合は任期途中でも突然「落選」という2文字でいきなり職を放り出されたりする、非常に苦労のある職業だ。彼らはこの時期、永田町の国会議事堂であれこれの法案や予算案や時にはそれらと全く関係ないことについて審議し、質問し、答弁し、この国の行く末をよりよいものにしようという素晴らしい努力を重ねている。

そしてこの国の未来を憂う人々は、国会で日々交わされる論戦の一部をニュースなり国会中継なりで耳にして、批判だったり称賛だったり、外野からあれこれとものを言ってその「観戦」を楽しんでいる。そういう人はTwitterで簡単に見つけることができるが、だいたいは自らの政治的主張、あるいは怒りや悲しみなどの感情に同調してくれる議員を支持し、それらを否定する議員を攻撃して元気に過ごしている。

その審議について色々言いたいこと――たとえば日本人の労働環境を悪化させまいと「たたかって」いる議員が質問を締切よりもずっとあとに出すせいで、官僚が深夜まで答弁を書かされていることとか――はあるのだけれど、とりあえずそれはおいておく。

その質問において、「イエスかノーかでお答えください」という手法を使う議員がいる。ひとりではなく、複数(試しに国会議事録の検索システムで「イエス ノー お答え」で検索したらここ5年間で199件ヒットした)。私が目にしたものはその全てが野党議員によるものだが、今の与党の議員も下野していた時代は使っていたのかもしれない。面倒なのでそこまで詳しく調べる気はない。

これが実にくだらないな、と苛立ったので、わたしはこの記事を書くことでそれを発散しようとしている。なぜくだらないのか、あるいはばかげているのか? ひと口で言ってしまえば、「イエスかノーかで答えることは聞き手に推測の余地――それもただの余地ではない、危険な余地だ――を生むから」。

これは全く自明なことだと思うのだが、念のため以下に説明を書いておく。

最初にことわっておくが、私は野党を批判するためにこの記事を書いているのではない(こう書いてもなお、私がこの記事で批判の矛先を向ける政治家の所属する党を攻撃したいのだと勘違いする人は一定数いるのだろう)。単にこういうことにばかばかしさを感じました、ということを書いているだけで、そこに一切の政治的カラーは関わっていない。上に書いたように与党でもこの手法を使ったことのある議員はいるかもしれない。この記事は個々の政治家への呆れを表明しているのであって、政治的には中立だと私は思っている。

とりあえずこの手法を用いる側の手口を書いておく。まず、彼ら(の代表者=議員)は上のように、すなわち「あなたは○○したんですか? イエスかノーでお答えください」と2択を突き付ける。内閣とか大臣とかまたは次官でも、政治を現在担っている側は質問されたらとにかく答えなければならない。彼らはこう答える――「えー、それについてはですね、まず△△ということがございましてですね、これにより、□□というものが発生するわけでございます。ですから……(以下略)」。そしてそれに対し質問した側は、「なぜ私が言った通りイエスかノーで答えないのか!」と憤慨し、「簡単なことだろう!」と批判し、よく嘲笑する。この嘲笑は私がTwitter上で目にしたもの、すなわち有権者のものだが、もしかしたら質問した議員本人も持っているかもしれない。こうして人々は「やっぱり(回答者)は間違っている。まともな受け答えもできない、まったく資質のない奴らだ」という自分自身の主張が肯定されたことに満足し、それをますます「正しい」ものとしてさらに強化していく。

そして最後に私がこれを目にして、ああ、またやってるな、と馬鹿馬鹿しさにかられ、本来療養に費やすべきエネルギーを浪費する。私は本当にTwitterを使うべきではないと思う。この登場人物のなかで最も愚かな人間は間違いなく私だ。

話が逸れた。

私は訊きたい。「あなた(の代弁者)が政権を奪ったとき、もし同じような質問をされたら『イエス』か『ノー』の一言で済ませられるのか? つまり、あなた方が相手に求めていることをあなた方自身は実践できるのか?」と。

分かりにくいので例を出そうと思う。最初からこうしておけばよかった。実はいま、加計学園というひとつの学校法人に関連して首相に疑惑の目を向ける人たちがいる。簡単に説明すると、加計学園が運営する某大学はこのたび数十年認められていなかった獣医学部の新設を認可されたのだが、この学園の学長だか理事長だかが首相の友人だった。そのため、首相がこのお友達のために認可への便宜を図ったのではないか? そうであるなら、これは職権の濫用で、全く許し難いことではないか? という風に問題視されているのだ。

この問題に対して立場を表明することはしない。論点がぶれるし、私が意図しなくてもこの記事を見る目が変わってしまうからだ。

私が取り上げるのは次の関連事項だ:実は全国の獣医師を束ねる日本獣医師会は、獣医学部の新設に強固に反対していた。「獣医学を教える教授は不足しているが、逆に獣医師は余っている。ゆえに獣医学部を作っても満足のいく獣医学教育を提供できないだけでなく、獣医師余りを加速させる」――理由はこんなところだ。この主張の是非も置いておく。

さて、いまの野党のK党の党首であるT氏という議員がいる(念のために仮名にしておく)。このT氏というかK党は加計学園問題を厳しく追及している。今の政権は嫌う人には激しく嫌われていて、T議員もたぶんその例に漏れない。

ここで問題が起こる。

『T議員、以下の質問にイエスかノーでお答えいただきたい。

「あなたは日本獣医師会から献金を受けたか?」』

ちなみに事実として、T氏は日本獣医師会から献金を受けている(重ねて申し上げるが私はこれに対していかなる意見も表明しない)。T氏はひとこと、「イエスであります、議長」とだけ言い、席に着くことができるだろうか?

私はできないと思う。なぜならそんなことをすれば「T氏はカネのために問題を作り上げて追及する、汚い政治家だ」という不名誉な解釈を一部の有権者に為されることは必至だからだ。

このあまりに短い質問文は、これを聞く者全員に詳細を解釈する余地を生んでしまう。「問題に関係する利益団体から献金を受けた」ということと「問題を一議員として追及する」ということは本来は別々に語られるべきことだが、このふたつが繋ぎ合わされて「献金を受けたから追及した」というストーリーが聞き手の脳内で作り出されることは非常に容易い。

これが「イエス/ノー質問」の最大の問題だ。一言で答えてしまえばその仔細は聞き手に委ねられ、時としてそれは回答者に非常に不利に働く。このケースで言えば、質問者の要求通りにイエスかノーで答えた場合、T議員は自らの印象を左右する「なぜこの問題を追及しているのか」について語る機会を与えられない。この短い質問とこれまでの事実から勝手に連想され、組み合わされて出来上がったものを有権者は保持するだろう。

おそらく高確率で、T議員はこのように回答をはじめるだろう――「そもそも献金というものはどの政治家も受けているものであって、私が特別ということはありません。すなわち、今この質問をされた先生方も同じように献金をどこかからされているのであります。ですから……」。これを流暢に言えるとは限らず、間に「えー」とか「あー」とかを挟むかもしれない(それを文字に起こすと、なんだかしどろもどろになっているような印象を受ける)。

T氏は、おそらく「はい、それはイエスです。ただし……」という答え方をしない。それどころか、回答の中に「イエス」という単語を入れることすらも避けたがるだろう。なぜならその部分だけが切り取られ、報道で、あるいは今ならばSNSで、自身に不利な解釈が為されるように拡散される可能性があるからだ。

現在この質問手法を使っている議員たちは、このこと――つまり相手が殆ど確実に質問の要求に応えないこと、そして一見するとそれが卑怯に見えるということ――を分かったうえで、なおこれを利用しているのだろうか? だとするなら、本当に卑怯なのはどちらであるのか?

ああ、この形式の質問を使う人々、そしてそれに眉をひそめず、それどころか「二択という簡単な質問にすら答えられないなんて!」と嘲笑する人々がこの世に存在し、私と同じ重みの一票を持っているという事実が全く持ってやるせない。それともこの私の論理に何か間違いがあるのだろうか、きっとそうなのだろう、そうに違いない。どんな人間――国語ができない人間、デマゴーグに踊らされる人間、そして自らの正しさを絶対として疑わない人間――も票の上では平等という民主主義自体にユートピア思想の片鱗を感じとり、そこから距離を置くという選択。それを選ぶ私はきっと「冷笑系」と呼ばれる人種で、この国をよくしようという熱意のない、ひどく無気力でゆえに無価値な人間なのだと。そして私がくだらなさを感じている人々こそが真の「人間」と呼ばれるべきものなのだと、そう主張したい。

アウトプットしても何も起こらない。この記事を最後まで読む人間はインターネットの海で見かけたひとつの記事で自らの思想信条を改められる人間だからだ。そしてそんな人間は最初からこんな手法を使わないし、これに利用されることもない。

この最後の命題も、一つの記事を読み終えたという特殊な行為からそれをなした人間の一般的な人間性にまで踏み込んだ結論を出しているという点で、明らかに飛躍している。

また心底くだらないことにエネルギーを浪費してしまった。「この記事がひどい! 大賞」があったら自分で最大まで投票したい。

連結リストのデータにポインタを使うのはいけないのか

さっきまでCで連結リストを実装していた。

その際、

typedef struct {

Data *data;
Node *next;

} LinkedList;

というように実装していた。

そしてうまく動作せずgdbデバッグしたりしてたんだけど、いくらやってもうまくいかない。 しかも、ググっても連結リストのデータ型をポインタにしてるものは全く見当たらない。

一体何がいけないんだろう。

C言語のポインタがやっぱりよくわかってなかったんだけどこの記事を書いてるうちにその部分はわかりました! わーい!

C言語の簡単なプログラムを作って構造体とポインタの挙動を調べているんだけど、やっぱりよくわからないところが出てきた。

まず、こう書いてみる。

#include <stdio.h>
#include "test.h"
#include <string.h>
#include <stdlib.h>

int zero = 0;

typedef struct{

    int *x;
} X;

typedef struct piyoo{

    X *piyo;
    struct piyoo *next_piyo;
} PIYO;


PIYO *make_piyo() {

    PIYO pi, *piyopiyo;
    piyopiyo = &pi;
    piyopiyo = malloc(sizeof(PIYO));
    piyopiyo->piyo = malloc(sizeof(X));
    
    piyopiyo->piyo->x = &zero; 
    piyopiyo->next_piyo = NULL;
        
    return piyopiyo;

}

void delete_piyo(PIYO *piyopiyo) {
    
    free(piyopiyo->piyo);
    free(piyopiyo);
}

int main() {

    
    PIYO *piyopiyo = make_piyo();   
    
    printf("piyo %d\n", *(piyopiyo->piyo->x));
    
//  delete_piyo(piyopiyo);

    free(piyopiyo->piyo);

    int y = 3;

    piyopiyo->piyo->x = &y;

    printf("3 %d\n", *(piyopiyo->piyo->x));

    free(piyopiyo);

    return 0;


}

何をしているのかというと、自己参照構造体PIYOを作り、PIYOはメンバとして構造体Xを持っている。このXの中身はint型のポインタだ。

で、いま関数make_piyoPIYOを初期化しょうとしている。このとき、PIYOの唯一の実体であるpiyopiyo->piyo->xの中身を0にしようとしている。

上のコードでは、piyopiyo->piyo->xグローバル変数zeroのアドレスを格納する、というやり方をとっている。

ところが、次のようにコードの該当部を変更するとセグフォする。

*(piyopiyo->piyo->x) = x;

関数make_piyoでは、PIYO構造体としての実体のpiを作り、そのアドレスをpiyopiyoに格納している。で、実体のpi.piyoが指し示しているポインタxの指し示す実体の内容を変えたかった。

本当はわからないので記事を投稿して反応を待とうと思ったんだけど、書いているうちに原因がわかってしまった。 PIYO構造体piが保持しているのはあくまでint型へのポインタ(つまり、アドレスを格納する場所)のみであって、そこに実体のintはない。だから実体に代入しろと言われても無理ですと言われるのは当然だ。

アウトプットしたり他人に説明したりすると理解できるようになる、ということが実験で証明されていた気がする。 アウトプットってすごい。