2017/03/31

[esp8266]Non-OS版もgithubに?

RTOS版の環境ができたので、ほかにESP8266のgithubに何か更新されたものがないか見ていたら、Non-OS版が2時間前にアップされていた。

espressif/ESP8266_NONOS_SDK: ESP8266 nonOS SDK

ESP8266を数ヶ月ぶりに見たその日に更新されるなんて、これはNon-OSに戻って来いという暗示だろうか?
でも、ソケットとか使うとスレッドがほしいのよねぇ。

 

私が探していたのは、ESP-TouchのAndroidソースだったのだが、それはここになかった。
が、EspressifAppという別のgithubアカウントにあるようだ。
https://github.com/EspressifApp

本物かなぁ。

[esp8266][rtos]RTOS環境のビルド

Bash on Ubuntu on Windowsの動きがあやしかったので、Xubuntu 16.04にESP8266のRTOS環境を作り直した。
以前も同じ作業をしたのだが、別VMになったから、復習も含めて書いておこう。
まあ、Arduino版を使っている人の方が多い気はするんだけどね。。。


今回は、$HOMEの直下にEsp8266というディレクトリを作り、そこで作業した。
ここを読んで、apt installが必要なものは済ませてある。
https://github.com/pfalcon/esp-open-sdk

$ mkdir Esp8266
$ cd Esp8266
$ git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
$ cd esp-open-sdk
$ time make STANDALONE=n

VMをHDD上に作っているし、あまりリソースを割り当てていないせいもあるが、40分くらいかかった。

$ cd ..
$ git clone https://github.com/espressif/ESP8266_RTOS_SDK.git

こちらはcloneするだけだ。

 

次は、環境変数などの設定。
.bashrcなどに置くか、使いたいときだけ設定するのかは個人の自由だ。
私は、使いたいときだけ設定するようにした。

$ mkdir rom

romディレクトリは、ビルド後にESP8266へ焼く物が置かれる場所だ。
SDK環境だとbinという名前なのだけど、binだと「ここに実行ファイルおいたっけ?」といつも思ってしまうので、名前を変えただけだ。

 

そして、HOME/Esp8266の直下にこういうスクリプトファイルを置いた。
私は「compile.sh」という名前にしたが、別にどうでもよい。
コンパイルできる環境変数を設定するためのスクリプトだから、名前は今ひとつだったか。。。

#!/bin/sh
export SDK_PATH=`pwd`/ESP8266_RTOS_SDK
export BIN_PATH=`pwd`/rom
export ESP8266_PATH=`pwd`/esp-open-sdk
export PATH=$ESP8266_PATH/xtensa-lx106-elf/bin:$PATH
export ESP8266_INCLUDE_PATH=$ESP8266_PATH/sdk/include
export ESP8266_LIB_PATH=$ESP8266_PATH/sdk/lib

これは、HOME/Esp8266ディレクトリで使うように`pwd`を使っている。

 

設定はこのくらいだ。
おまけで、こういうスクリプトファイルを作って、オリジナルのgen_misc.shと置き換えている。

ESP8266 RTOSビルド用gen_misc.sh

いつもgen_misc.shするたびにコンソールで答えていくのが面倒なので、自分がよく使う設定を書いただけだ。
うちはWROOM-02なので、各自好きに変更するのもよし、使わないのもよし、だ。


試しにビルドしておこう。

$ source compile.sh
$ cd ESP8266_RTOS_SDK/examples/wps_demo
$ (gen_misc.shを置き換えた)
$ ./gen_misc.sh

うまくいくと、rom/upgrade/user1.4096.new.6.binができているので、それをESP8266へ焼けばよかろう。

ただ、ESP8266のWPSはAPによってうまくいかないものがあったので、正しく動くかどうかは保証できん。
それに、デフォルトだとうちのUSBシリアル変換ではアクセスできないbpsでログが出てくるので、うまくいったかどうかわからん。
試す場合は、その辺に気をつけるのがよかろう。

[esp8266][rtos][bow]RTOS SDKを更新しようとしてあきらめる

久しぶりに休暇を取ったので、ESP8266のRTOS版で遊んでみよう。
と思ったが、インストールしてから長いこと放置しているので、RTOSの部分が古くなっているかもしれない。
更新しておこう。

環境は、Windows10 64bitのBash on Ubuntu on Windowsだ。


RTOS SDKは、昔はEspressifからダウンロードしていたのだが、今ではgithubで管理されている。
espressif/ESP8266_RTOS_SDK: Latest ESP8266 SDK based on FreeRTOS

Non-OS版はコンパイラも一緒になっていたのだが、RTOS版ではgcc推奨になっていて、それはesp-open-sdkと呼ばれているようだ。
pfalcon/esp-open-sdk: Free and open (as much as possible) integrated SDK for ESP8266/ESP8285 chips

だから、この2つを更新する必要があろう。


まずはesp-open-sdkから。
https://github.com/pfalcon/esp-open-sdk#building

さて、STANDALONEはyだったかnだったか。。。
http://hiro99ma.blogspot.com/2016/12/esp8266esp-open-sdkstandalonen.html
ここを見ると、nでやっているように見える。

 

が、不安が。
当時の私はSTANDALONE=nの方がライセンス的に大丈夫そうだ、という判断をしているのだが、その翻訳は正しかったのだろうか?

To build the bare Xtensa toolchain and leave ESP8266 SDK separate

この一文の「separate」だけで判断していなかっただろうか。
ちゃんと英文を読もう。

Build

プロジェクトは2つのビルドモードがある。

  1. バイナリも含め提供されるベンダのIoT SDKから切り離す。ライセンスもクリアで、ベンダのSDKアップデートにも対応しやすくなる。
  2. 完全にツールチェーンがマージされたベンダのSDKファイルからも分離する。このモードはソフトウェアのビルドを容易にする(-Iや-Lなどを追加せずに済む)。しかし、ビルドしたものの再配布はライセンスがクリアではなく、ベンダが提供する新しいバージョンのIoT SDKリリースが行われると複雑になる。このモードはローカルビルドとしてデフォルトだ。(以下略)

というわけで、1がSTANDALONE=nだと思う。
2はデフォルトと書いてあって、makeの引数無しはSTANDALNE=yだからだ。

 

では、git pullしてmakeしなおそうと思ったが、よくわからんエラーが。。。

fatal: index file open failed: Input/output error

不思議なことに、このエラー自体はフォルダを移動したりしているうちに直った。
どうも、BoWはファイル周りがまだ弱いような気がする。

もう一度git pullすると、今度は「examples/blinky/Makefile」がどうのこうのと。
git statusしてみると、Changesの方にdeletedでずらずらファイルが並んでいる。
そこにexamples/blinky/Makefileも入っているのだが、実際にはファイルがある。。。
そして、Untrackedの方にはexamples/が入っているのだ。
もう、何が何だか。。。

では、examplesをexamples_にリネームしよう。

$ mv examples/ examples_
mv: cannot move 'examples/' to 'examples_': No such file or directory

はあ?

$ mv examples/ examples_
$

2回同じことをやったら動いた。
これ、BoWでgo言語をやったときにも出てきたな。
これをしても、まだexmaples/blinky/Makefileがどうのこうのというから、BoWが原因で起きているような気がする。

 

気がする程度ではあるが、不安な環境でやるような作業でもないので、VMのLinuxでやろう。。。

2017/03/30

IBMのhyperledgerは今のところ6ノードまで

ニュース解説 - 「ブロックチェーン版Linux v1.0」は世界を変えられるか:ITpro
あー、hyperledgerって名前はときどき聞くけど、なんだっけ?
IBMがやってるとかなんとか。。。

 

Hyperledger Quick-Start Guide
IBMがやってるのは「Fabric」というやつで、「Sawtooth Lake」というものもあるようだ。
まあ、オープンソースといっているからIBMだけがFabricをやっているわけでもないのだろうが、「hyperledger = IBM」というわけでもないということだ。

2017/03/31追記
hyperledgerは2つと書いたが、現時点では4つあるとのこと。
http://stackoverflow.com/questions/41710738/pbft-algorithm-in-hyperledger

これが1月の投稿だから、もっとあるのかも。

 

Fabricは、参加できるノード数が6となっている。

image

銀行なんかで使うのだったら、そんなにノードはいらないよね、ということかもしれん。
ただ、ノードが6つくらいで、許可した人しか参加できないのだったら、データベースで十分じゃないの?という気もする。
ブロックチェーンは単なる道具だから、使いどころによるのか。

 

「ブロックチェーンを使った方が運用コストが下がる」という話もあったのだけど、DBと比較してだろうか?
元記事を探すことができなかった。。。
それだったら、Oracleが反論記事とか書いてそうな気がする。
検索して上の方にあったのがこれだけど、読む知識と英語力が足りん。。。
The Benefits of Blockchain Across Industries

 

仕事柄、ブロックチェーンのことを聞くことが多いのですが、良い悪いは別として、予算がどうのとか、大人の都合とかが多くて、技術だけやってる私にとっては疲れる。。。
まだ技術屋さんの範囲で盛り上がる段階のものが、お金の臭いを嗅ぎつけた人たちのところまでいってしまった、という感じがしなくもない。
まあ、お金は大事なのだけど、技術よりお金の方が先に出てしまって、連載中の漫画をアニメ化したのは良いけどアニメの方が追い越してしまってお茶を濁して間を持たせる、みたいなことになるのが心配だ。

2017/03/28

[js]グローバル変数の初期値はundefinedという値らしい

未だにJavaScriptをやっている。
あと数日のりきれば、おさらばできる(はず)。。。

 

先日、関数間をまたがる変数がほしくて、グローバル変数を使った。

  • 関数の外でvarを付けて宣言
  • 関数の中でvarを付けずに使用

のどっちからしい。
今回は連想配列をグローバル変数にしたかったので、こんなコードを書いた。

if (global_val[xxx] == null) {
  global_val[xxx] = yyy;
}

どうせ初期値はnullだろうと思ったのだ。
が、これはダメだった。

どうやら、初期値はundefinedというグローバル変数らしい。
また、undefinedという変数は代入可能なようで、==で比較するのは良くないと書かれていた。
そんなの知るか!ということで、こう変更した。

if (global_val[xxx] == undefined) {
  global_val[xxx] = yyy;
}

が・・・これもダメ。

if ((global_val == undefined) || (global_val[xxx] == undefined)) {
  global_val[xxx] = yyy;
}

たしか、こんな感じに変更してようやく動いたと思う。
やれやれ。

 

個人の感想だが、先に入れ物の有無を確認する必要があるのだったら、入れ物を初期化する処理も書くようになっていた方がわかりやすかったんじゃなかろうかと思う。

if (global_val == undefined) {
  global_val = new 連想配列作る();
}
if (global_val[xxx] == undefined) {
  global_val[xxx] = yyy;
}

この辺りは、私がJavaScriptの気持ちになりきれていないからだろう。
説明を読んで勉強しておこう。
var - JavaScript | MDN

 

困ったことに、今使っているのがmeteorというフレームワークで、これはjsファイルをincludeして関数化してしまうらしい。
だから、関数外でvarを付けて変数宣言しても、グローバル変数にはなってくれないとのこと。
いきなり関数内で知らない変数名が出てくるとあせるので、関数の外にvar無しでundefinedでも代入しておくのが良いのかなぁ。

[bc]アドレスのこと

技術ネタが切れてきたので、仕事でやってることに触れない範囲で、ときどきBitcoinのことを書いてみよう。
そういうときは「あ、ネタがないんだな」と思ってほしい。。。

今回は、Bitcoinアドレスについて書こう。
昔のBitcoinについてはあまり知らないのと、お金がかかる方のBitcoinを使ったことが無いので、。


ビットコインアドレスとは

読んでもらえばわかるので、これでおしまい、ではあんまりなので、もう少し細かいことを書くことにする。

「標準のビットコインアドレスは1で始まり」とあるが、そもそも標準ってなによ?というのが気になると思う。
Bitcoinはいろいろと仕様があって、アドレスについても決まりがあるのだ。

まず、お金になるBitcoinのブロックチェーンと、お金にならないBitcoinのブロックチェーンがあることは知っておいても良いだろう。
お金になる方は「mainnet」、お金にならない方は「testnet」と呼ぶ。
まあ、他にもあると思うが、主にこの2つだ。

「1」で始まるアドレスは、mainnetの方に属するアドレスである。
同じタイプでtestnetに属するアドレスは「m」や「n」で始まる。
だまされないように注意しよう。

 

その隣に「よりセキュリティーの高いマルチシグアドレスは3で始まる」と書かれている。
https://bitflyer.jp/ja/glossary/Multisig
うーん、その説明はどうよ?という気がしなくもないが、長く説明してもどうしようもないので、ここら辺が落としどころなのかもしれん。

まず、マルチシグのアドレスは「3」で始まるが、「3」で始まるアドレスがマルチシグとは限らない、というところがある。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#base58
(すまん、日本語版もどこかにあったと思うが、見つけられなかった。。。)

リンク先に飛んで、スクロールさせていき「Table 4-1」を見てほしい。
Typeが"Bitcoin Address"が、さっき出てきた「1」で始まるアドレスの話だ。
"Base58 result prefix"に"1"と書いてあるのがわかる。
その2つしたに"Bitcoin Testnet Address"が"m or n"となっているのもわかるだろう。

で「3」だ。
これのTypeは"Pay-to-Script-Hash Address"と書かれている。
通称「P2SH」で、「1」で始まるアドレスが直接口座に振り込まれるようなアドレスだとすれば、「3」で始まるアドレスはスクリプトというプログラムに対して振り込まれるアドレスで、そのプログラムを解けないと振り込まれたBitcoinを使うことができないしくみになっている。
マルチシグも「n人のうちm人の署名がないと使うことができない」というスクリプトで表現するようになっているので「3」で始まるのだ。

これもtestnetで使うアドレスだと違う文字で始まる。
表に載ってないけど「2」のはずだ。
数字で始まるからmainnetのアドレス、というわけではないのだ。。。


ちなみに、Bitcoinはアドレスが分かると、そのアドレスに振込が行われたり、誰かに振り込んだりしたという状況がネットで確認できる。
いくつかそういうサイトがあり、私はBlock Explorerというサイトをよく使っている。
https://blockexplorer.com/

"Latest Transactions"というところが更新され続けていると思うが、これが振込の状況だ。
どれか1つクリックすると画面が変わって、いくつかBitcoinアドレスと額が出てくると思う。
左側にBitcoinアドレスが振り込む側で、右側のBitcoinアドレスが振り込まれる側だ。

よくあるパターンは、左側が1つのBitcoinアドレス、右側が2つのBitcoinアドレスかな。
Bitcoinは銀行の口座と違って、一部だけ支払うということをしない。
だから、誰かへの支払いがあると、残りはお釣りとして自分が使うBitcoinアドレスに振り込むことになる。
振り込んだのと同じアドレスに入れても良いのだけど、セキュリティ的によろしくないので、普通は別のBitcoinアドレスを作って、そこに振り込むだろう。

そういう面倒なことは、だいたいBitcoinの財布に当たるウォレットアプリがやってくれる。
ただ、信頼性のないBitcoinウォレットを使ってしまうと、勝手に別のアドレスに振り込んだりするかもしれないので、とにかく有名で安心できるものを選ぶようにしよう。

ここで自作のウォレットアプリを紹介できるとよいのだろうけど、全然そういうものを作る自信がないですな。
心配だったら、ハードウェアウォレットというネットから物理的に切り離したウォレットがあるので、そういうのがよいのだろうね。

2017/03/26

[勉]最近のPCのブートを知る (3) : ブートマネージャー

ここまで調べたところで、パーティションテーブルの扱い方に新しいやり方が加わったということがわかった。
まあ「新しい」といってもずいぶん前からなのだが。。。

もう1つ気になっていることがある。
外付けUSB-HDDにLinuxをインストールしたのだが、起動ディスクを選択するときにOS名が出てきたのだ。
そして、そのUSB-HDDを同じ機種である別のPCに挿したのだが、OS名も出ないし、起動するドライブとしてインストールしたディスクやパーティションを選択しても起動できなかったのだ。

UEFIにブートマネージャーなるものがあるようだが、それが関係しているのだろうか?


https://ja.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface#.E3.83.96.E3.83.BC.E3.83.88.E3.83.9E.E3.83.8D.E3.83.BC.E3.82.B8.E3.83.A3.E3.83.BC

どうも、特定のセクタ(ブートセクタ)を読込んで起動を始めるのではなく、「ここにロードするファイルがある」という情報をUEFIに教えておき、UEFIはNon-Volatileなメモリにそれを保持しておいて、それを使って起動するようだ。
ブートセクタに何も書いていないのなら、それはUSB-HDDだけ挿しても立ち上がらないはずだな。

そのロードするファイルは、OSに依存しない場所に置かれ、OSに依存しない形式のフォーマットで、OSに依存しない実行形式なり情報なりが書かれているはずだ。
そして、インストーラがそれをUEFIに教えることになるから、何かしらのAPIというかABIというか、そういうので通信していることになるだろう。
それがPEというやつか。

ここら辺までひっくるめて「UEFI」と呼んでいるような気がする。
ディスクだけ挿して起動するという時代は終わったのか。。。

ただ、USBメモリにISOファイルを書込んで起動することができるから、できないというわけではない。
そういうブート形式でインストールされていないだけなのだろう。
VirtualBoxみたいに、移動できてどこでも同じように動くLinux環境を作りたかったのだが。

ブートセクタにブートローダを書込んでおいて、UEFIから起動するときにブートセクタを読込んでくれるようであれば、動く気がする。
ブートローダをどこに書込むかは、インストーラが聞いてくるので指定できる。
ドライブの方に書込むのか、パーティションの方に書込むのかいつも迷うのだが、さっきの話からするとUEFIに登録するようなものになるから、どこでもよいのかもしれない。

ブートローダー - ArchWiki
読んだときは、2017年1月更新になっている。
Linuxのブートローダって、たくさんあるんだな。。

Ubuntu系はGRUB2というか、GRUB(Legacyではない方)が使われていたと思う。
GRUB - ArchWiki
保護用にパーティションを作るなどと手順が書かれているが、私は何も考えずに「/」とswapのパーティションしか作らずにインストールしたので、そこらへんがよくなかったのかも。
Linux 上の GRUB 2 がブートできなくなったときの対処方法
リムーバブルディスクから起動できると書いてあるしね。

そういえば、Raspberry PiもbootはFATパーティションに置いてあるから、そういうのがいるのかもしれん。
まあ、今回は最近の情報を調べたかっただけなので、これで終わるとしよう。

2017/03/24

[勉]最近のPCのブートを知る (2) : UEFIモードとBIOSモード

UEFIのWindowsをBIOSモードで起動させる « ライフボート 裏ブログ(非公式ブログ)
どうも、UEFIはBIOSとは別物のようだ。
前回見ていったMBRやGPTは、どちらかといえばディスクのフォーマットに関するものだが、それだけでは済まないらしい。

 

UEFI モードまたは従来の BIOS モードでの起動
Microsoftのページで、まだWindows10は入っていない(別のページにあるのかもしれんが)。
UEFIモードの場合はGPTで、BIOSモードの場合はMBRと書いてある。

うちのノートPCはどうだっけ、と管理画面を見てみると、UEFIモードのようだ(EFIという文字があったので)。

image

 

Unified Extensible Firmware Interface - Wikipedia
ディスクの管理についても書かれているが、MBRもあればGPTもある、という感じで、別にGPTだけとなっているわけではなさそうだ。
もしかすると、MBRもある、がBIOSモードのことかもしれんが、さすがにそこまではわからん。

読んでいくと、BIOS時代から考えるとかなり高機能になっていることがうかがえる。
組み込みでも、RedBootやuBootの用に1段目のブートローダを使うことがあるが、そういう位置づけなのかもしれん。
あれが提供されているおかげで、あまり考えずにLinuxなどが動かせたりするからな。


だんだんまとまりがなくなってきたが、そもそも「最近のPCブートを知る」という漠然とした内容だから仕方あるまい。

2017/03/22

[勉]最近のPCのブートを知る (1) : MBRとGPT

まずは、UEFIから調べる。

BIOSに代わるファームウェア“UEFI”とは一体何か? 1/2 | 震撼性能! Sandy Bridgeに死角なし!! | DOS/V POWER REPORT

DOS/V POWER REPORTだから、PCを自作する人向けの情報ではあるものの、ポイントが絞られている分わかりやすい。

  • 起動ドライブの容量制限がなくなる(実質的に)
  • 設定画面がGUIにできる

今回はブートのことを知りたいだけなので、前者だけ見ていく。


Master Boot Record(MBR)の管理しか知らなかったのだが、GUID Partition Table(GPT)という管理があるらしい。

MBRは、HDDなどのセクタ0にパーティション情報が書いてある形式・・・と思っていたが、セクタ0だけじゃなくてパーティション分けされた先頭セクタでも良いようだ。
マスターブートレコード - Wikipedia

昔のHDDはCHS方式でアクセスしていたけど、容量が足りなくなってLBA方式になった。
SATAになる前のパラレルなHDDは40ピンあって、けっこうな本数がLBA用に割り当てられていたような記憶がある。
Advanced Technology Attachment - Wikipedia

パーティションテーブルのオフセットが8byte目のところがLBA方式で、サイズが4byteしかないというのが「MBRは32bit管理」という部分だろうか。
でも、これは先頭位置だけだから、その次の「全セクタ数」が4byteになっている方が32bitで制限される原因としては大きいのか。


GUIDパーティションテーブル - Wikipedia
こちらがGPT。
なんとなく肝臓付近を意識してしまうが、γ-GTPなんかとは関係がない。

LBAのアドレス表記で言えば、こうなっているそうだ。

  • LBA0 : MBRに相当する情報
  • LBA1 : GPTヘッダ
  • LBA2~33 : パーティションエントリ

GPTで管理していても、GPTに管理していないツールなどのためにMBRを用意してあるのだと。
MBR部分をどう見るかはOSによって異なるらしいので、自分でパーティションテーブルを作るときには注意した方がよさそうだ。

 

名前の由来になっているGUIDがどこに出てくるかというと、パーティションエントリという部分のようだ。
図によると1つのセクタに4エントリ入るようなので、512byte / 4 = 128byte/エントリ、ということになる(HDD系の1セクタサイズって、まだ512byteでよいよね??)。

  • 0- 15 [16]: パーティションの種類を表すGUID
  • 16- 31 [16]: パーティション固有のGUID
  • 32- 39 [ 8]: パーティション開始LBA
  • 40- 47 [ 8]: パーティション最後LBA
  • 48- 55 [ 8]: 属性フラグ
  • 56-127 [72]: パーティション名(UTF-16LE)

後半はわからなかったので、英語版wikipediaの情報を使った。
https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_entries


そこそこに衝撃だったのは、fdiskではGPTを扱えない、ということを知ったことだろうか。
まあ、Raspberry Piくらいだったらfdiskで済んでいるのだけど、PC Linuxが起動しないときに自分で対応しようとして悩まないように・・・というか、よけい破壊しないように覚えておいた方が良かろう。

[勉]最近のPCのブートを知る (0)

「PC」と書いたが、WindowsやLinuxがインストールできるような、お店でマザーボードやCPUを買って組み立てるようなPC、というのが正しいかもしれん。
昔だと「DOS/V互換機」などと呼んでいたように思うが、最近の名称がわからん。
また、Macは文化が異なりそうなので、今回は除外する。

 

なんで今さらブートのことを調べようと思ったのかというと、知識が追いついていないからだ。
作業に支障が出ることを心配するくらいには、取り残されてしまっている。

今回は、なんで調べようと思ったのかを記録しておこう。


昨年買ったノートPCに、今はWindows10がメインでインストールされているが、VirtualBoxでUbuntuもインストールしている。
しかし、ゲストOSではパワーが足りないので、外付けSSDにネイティブLinuxをインストールしようと考えた。

外付けSSDと書いたが、実際は外付けHDD(BuffaloのHD-PLFU3)を持っていて、蓋を無理やりはがして余っていたSSDを取り付けたのだ。

USBメモリにLinuxインストーラのISOファイルを焼いて、USBメモリから起動し、外付けSSDにインストールすることはできた。
ブートローダをどこに書込むか聞かれたので、外付けSSDの一番上(パーティション番号が付かないところ)を指定した。

 

その外付けSSDを持って作業場に行った。
実は、家のノートPCと作業場のノートPCはほぼ同じ機種だから、全部外付けSSDに書込んでいるから接続すれば起動するだろう、と軽く考えていた。
しかし、起動しなかった。。。

よくわからないが、面倒なので、インストールに使ったUSBメモリを挿し、インストールし直すことにした。
しかし、これはインストーラのせいか何か分からないが、うまくいっていない。

 

こうやって考えていくと、自分のブートに関する知識がまったく役に立っていないことが分かる。
当時はBIOSが主流だったが、今はUEFIとかいうやつだ。
パーティションも、だいたいprimaryで4つまで分割するのが主だったと思う。

 

などと振り返っていくと、このままの知識では仕事に影響が出るんじゃなかろうか、と心配になった。
心配なら、調べて安心しようではないか、と思ったのだ。
それに、何がどうなっているか知っていないと、心配どころではなく、作業に差し障りが出てしまう。
ブログにするネタもないことだし、しばらく調べるとしよう。

2017/03/21

[c/c++]main関数の引数

最近、本業が忙しく、記事の更新ができてないし、書くネタがない。。。
1週間空けるのも嫌なので、Cのmain関数のことを調べ直すことにした。

 

普段フリースタンディング環境を使うことが多いので、main関数はあってもなくてもよいというか、名前は何でもよいけど慣習として使っておこう、くらいのイメージしか持っていない。
関数とは書いたけれども、returnされてもやることがないので、スタックを消費するのも嫌だからコールじゃなくてジャンプさせている、という人も多いんじゃなかろうか(そしてmainの最後は無限ループになっている)。

 

ただ、普通のホスト環境では、main関数は重要だ。


今回もオライリーの『Cクイックリファレンス』を読む。
「7.1.5 main()関数」だ。

  • int main(void)
  • int main(int argc, char *argv[])

この両者がC標準とのこと。
引数無しでもいいんだ。。。

これに加えて、次の形式もサポートしていることが多いのだと。

  • int main(int argc, char *argv[], char *envp[])

envpは環境変数で、getenv()を使ってアクセスできるそうだ。

 

main()の特徴として、returnを書かずにブロックが終わった場合、自動的に0を返すことになっている。
そして、0はstdlib.hのEXIT_SUCCESSと同じ値。
また、main()の終了は、exit()の呼び出しと等価とのこと。

exit()はちょっと特別扱いされていると思っていたのだ。
atexit()でexit時に呼び出す関数が登録できるというところが不思議だったのだ。
説明文を読むと「exit()かmain()のreturn」と書かれているので、同じ扱いなのだな。


昔、C++で作っていたとき、グローバル変数で2つのclassのインスタンスをそれぞれ作り、片方のclassがもう片方のclassのstatic値をコンストラクタで参照するようにしていたのだが、最初は動いていたのに、プログラムを書き換えているうちにうまく動作しなくなった、ということがあった(あまり覚えてないが。。)。

グローバル変数のコンストラクタはどういう順番で動くかはっきりせず、コンストラクタが呼ばれていないと値が設定されないので、最終的にはコンストラクタで初期化は行わず、classに初期化関数を追加してmain()で呼ぶ、というような対処をしたような気がする。

mainが呼ばれる前後の混沌とした状態は制御が難しいので、なるべくmain後の安定した状態で処理を順番に行った方がよいな、と思ったのでした。

2017/03/14

[c/c++]asctime()は改行を含む

EPOCH秒を使っているところがあったので、日付形式で表示させたいと思った。
標準関数って、便利だわ。

 

01: #include <stdio.h>
02: #include <time.h>
03: 
04: int main(int argc, char *argv[])
05: {
06:     time_t now = time(NULL);
07:     printf("now(%s)\n", ctime(&now));
08: 
09:     return 0;
10: }

結果

now(Tue Mar 14 09:42:57 2017
)

 

なんだ、この改行は。。。
と思ったが、asctime()は改行を含めた文字列を返す仕様らしい。

 

まあ、それが嫌だったらstrftime()を使って自分で文字列を作れということなのだろうが、なんでわざわざ改行を含めた文字列を生成しようと思ったのだろう?
普通に\0で終わっておけば、改行するなどはこちらで勝手にやるのに。

pythonにも同じような関数があるのだが、わざわざ「Cとは違って改行は含まない」と書いてあるように、だいたいの人にとって不要と思われているのだ。
https://docs.python.jp/3/library/time.html

 

一度付けてしまったのでそれ以降は外せなくなった、という経緯だろうから、当時は何か理由があったのだろう。。。

2017/03/11

[c/c++]static libraryでAPIを隠すのにもvisibility("hidden")が使えそう

以前、static library(*aというやつね)で、複数ファイルにまたがって使う関数があるけど、外には公開したくないものがあったので、なんとか隠せないかと考えたけど、ダメそうだった。
[c/c++]static libraryで非static関数を隠すのは無理そうだ

 

まあよかろう、と思っていたのだが、ライブラリの機能を追加しているうちに、別のファイルで使っているstatic変数にアクセスしたい状況が発生してしまった。。。
setter/getterを用意すれば使えるものの、それも公開関数になってしまう。
公開しているヘッダファイルに書かなければ使おうとは思わないだろうし、そもそも内輪で使うライブラリなので「使うなよ」で済ませられるのだけど、nmで見るとわかるし、格好が悪い。

 

また調べ始めたところ、これが見つかった。
c - Restricting symbols in a Linux static library - Stack Overflow

前回、shared libraryでしか使えなさそうだと思っていた__attribute((visibility("hidden")))が使えそうなのだ!


まず、ライブラリのソースファイルを用意。
中身はてきとうだ(ちなみに、私は「よしだ」でも「よしお」でもない。"foo", "bar"みたいな感じで使っている。)。

yoshida.h

01: #ifndef YOSHIODA_H__
02: #define YOSHIODA_H__
03: 
04: int yoshida(void);
05: 
06: #endif /* YOSHIODA_H__ */

yoshida.c

01: #include <time.h>
02: #include "yoshida.h"
03: 
04: int __attribute__((visibility("hidden"))) yoshida(void)
05: {
06:     return (int)time(NULL);
07: }

yoshio.h

01: #ifndef YOSHIO_H__
02: #define YOSHIO_H__
03: 
04: int yoshio(void);
05: 
06: #endif /* YOSHIO_H__ */

yoshio.c

01: #include "yoshio.h"
02: #include "yoshida.h"
03: 
04: int yoshio(void)
05: {
06:     return yoshida() * 2;
07: }

yoshida()がライブラリ内だけで使う関数、というイメージだ。

まず、普通にビルド。

$ gcc -O0 -c yoshida.c
$ gcc -O0 -c yoshio.c
$ ar rv yoshi.a yoshida.o yoshio.o
$ nm yoshi.a

yoshida.o:
                 U time
0000000000000000 T yoshida

yoshio.o:
                 U yoshida
0000000000000000 T yoshio

どちらも「T」なので、外部からリンクできる状態だ。

 

で、Stackoverflowに書かれている方法はobjcopyを使うのだが、objcopyはinfileが1つだけのようだから、oファイルを1つにまとめてから実行することになるのかな。

$ ld -r yoshida.o yoshio.o -o yoshi.o
$ nm yoshi.o
                 U time
0000000000000000 T yoshida
0000000000000010 T yoshio

うむ、まとまったようだ。

$ objcopy --localize-hidden yoshi.o yoshi_hidden.o
$ nm yoshi_hidden.o
                 U time
0000000000000000 t yoshida
0000000000000010 T yoshio

おお!
yoshida()が「t」になった!


では、これはグローバル変数でも適用できるのだろうか?

 

yoshida.h

01: #ifndef YOSHIODA_H__
02: #define YOSHIODA_H__
03: 
04: extern int __attribute__((visibility("hidden"))) g_yoshida;
05: 
06: int yoshida(void);
07: 
08: #endif /* YOSHIODA_H__ */

yoshida.c

01: #include 
02: #include "yoshida.h"
03: 
04: int __attribute__((visibility("hidden"))) g_yoshida = 0;
05: 
06: 
07: int __attribute__((visibility("hidden"))) yoshida(void)
08: {
09:     g_yoshida = (int)time(NULL) >> 2;
10: 
11:     return (int)time(NULL);
12: }

yoshio.h

01: #ifndef YOSHIO_H__
02: #define YOSHIO_H__
03: 
04: int yoshio(void);
05: 
06: #endif /* YOSHIO_H__ */

yoshio.c

01: #include "yoshio.h"
02: #include "yoshida.h"
03: 
04: int yoshio(void)
05: {
06:     return yoshida() + g_yoshida;
07: }

$ gcc -c -O0 yoshida.c yoshio.c
$ ld -r yoshida.o yoshio.o -o yoshi.o
$ nm yoshi.o
0000000000000000 B g_yoshida
                 U time
0000000000000000 T yoshida
0000000000000023 T yoshio


$ objcopy --localize-hidden yoshi.o yoshi_hidden.o
$ nm yoshi_hidden.o
0000000000000000 b g_yoshida
                 U time
0000000000000000 t yoshida
0000000000000023 T yoshio

おお、「B」が「b」になった。
B/bはBSSのBで、未初期化データ。
なお、初期値がある場合はD/dとかG/gとか。


ここで安心してはいけない。
ちゃんと、リンクさせてみなくては。

test.c

01: #include 
02: #include "yoshio.h"
03: #include "yoshida.h"
04: 
05: int main(int argc, char *argv[])
06: {
07:     int a;
08: 
09:     a = yoshio();
10:     printf("data=%d\n", a);
11: 
12:     a = yoshida();
13:     printf("data=%d\n", a);
14: 
15:     a = g_yoshida;
16:     printf("data=%d\n", a);
17: 
18:     return 0;
19: }

$ gcc -o tst test.c yoshi_hidden.o
/tmp/ccMESvZf.o: In function `main':
test.c:(.text+0x2c): undefined reference to `yoshida'
test.c:(.text+0x49): undefined reference to `g_yoshida'
/usr/bin/ld: tst: hidden symbol `g_yoshida' isn't defined
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

うむ、yoshida()もg_yoshidaもリンクできていない(ヘッダに書いているから、コンパイルはできる)。


今回は、ldでオブジェクトを1つにまとめたものをobjcopyしたが、arで固めたものでもobjcopyで--localize-hiddenできるのだけど、そうしてしまうとライブラリ内ですらhiddenされてしまうので、今回だとyoshio()がyoshida()を参照できなくなってしまう。
だから、オブジェクト内で完結できるようにしてから--localize-hiddenすることになるだろう。

 

-xで「t」や「b」を隠すことができるかと思ったけど、それはできなかった。
残念な気もするが、見栄えは気にしないので、追わないことにする。

 

g_yoshidaに0を代入している。
[c/c++]0を代入したグローバル変数は初期値ありと見なされないようだ
0を代入しても、初期値ありとは見なされず、BSSとして扱われる。
しかし、0を代入しなかった場合、今回は「B」ではなく「C」で扱われていた。

$ nm yoshi_hidden.o
0000000000000004 C g_yoshida
                 U time
0000000000000000 t yoshida
0000000000000023 T yoshio

Cはコモンシンボルというやつで、これは小文字のcがない。つまり、グローバルしかない。
test.cでg_yoshidaにアクセスしたが、リンクも通った。
commonって何だ? nm 謎解き編 - toshi_hirasawaの日記
そういう性質があるので、面倒なことにならないよう、初期化しておく方が無難かも。

2017/03/10

[py2]16進数値と16進数文字列

何度やっても覚えられない、python2での16進数と文字列の変換。

 

16進数値を、16進数文字列に変換
http://hiro99ma.blogspot.com/2017/01/py216str.html

>>> x = 0x0123456789abcdef
>>> format(x, '016x')
'0123456789abcdef'

 

16進数文字列を、16進数値(というか、数字)に変換

>>> y = '0123456789abcdef'
>>> int(y, 16)
81985529216486895L
>>> format(int(y, 16), 'x')
'123456789abcdef'

 

これでしばらくは大丈夫なはずだ。。。

2017/03/09

[js]nullは0じゃない

今日、ちょろっとJavaScriptを触っていた。
もちろん、詳しくない。
最近触っているというか、触らざるを得ないからやっているのだが、とてもつらい。。。

 

今日は、グローバル変数と呼んで良いのか? varを付けずにアクセスする変数を作りたいと思った。
とにかくカウントアップする変数を用意したかったのだ。

ただ、どこから呼ばれるかはっきりしないので、初期化するタイミングに悩んでいた。
そういえば、変数に代入されてないことの確認で、

if (!value) {
  ...
}

みたいに書けたと思うから、初期値は0ってことじゃなかろうか。

ということで、こう書いた。

count++;

 

はい、動きませんでした。。。
たぶん、例外が発行されたのだと思う。
meteorを使っていたから、meteorが例外を出していたのだけど、たぶんそうだろう。

デバッグ用だったから、onRendered(meteorのしくみね)で

count = 0;

とすると、動いた。

なるほど、0じゃなくて、nullなんだ。
そして、nullだからインクリメントなんてしたらいかんのだな。

 

普通のJavaScriptだったら静的解析ツールなんかに掛けることもできそうだけど、meteorだと文法がちょっと違うためか、うまくいかなかった。
C/C++を主に使っているので、コンパイルエラーが出なければそこそこ動くだろう、と思ってしまうのだが、そうじゃない世界に放り込まれると、けっこうつらいですわ。

[c/c++]先頭にアンダーラインを付けようとしたが、やめた

前回の続きだ。

static library、まあ「*.a」のファイルと思ってもらえば良いか。
そのタイプだと、単にオブジェクトをまとめただけなので、オブジェクト間で共有したい関数をstaticにすることができない。
だから、リンクする人には見えてしまう。

 

今まで、それが嫌な場合は、#includeでソースファイルをインクルードさせることで、ファイルだけ分割させることがあった。
目的は果たせるのだけど、すっきりしないので、コンパイラ依存でも良いから方法があるなら何でもよかったのだ。
しかし、方法がまだ見つかっていない。。。

 

そこでふっと思い出したのが、アンダーライン「_」だ。
システムなどが使うから、先頭にアンダーラインを付けた名前はいかんよ、というルールだったと思う。
今こそ、そのアンダーラインを使うときでは無かろうか?

・・・アンダーラインを付けないようにしたルールって、なんだっけ?


今回は、オライリー『Cクイックリファレンス』で調べる。
どの章になるのか分からなかったが、「16章 標準ヘッダ」の、"16.1.3 予約識別子"がよかろう。

思ったより、幅広いルールだった。

  • 2つの下線または下線の後に英大文字から始まる識別子は予約済み
  • 下線から始まる他のすべての識別子はファイルスコープで識別子として予約済み

えーっと、まず、下線2つはダメ。
下線1つと大文字も、ダメ。

ファイルの中で閉じているなら、下線1つと小文字ならOK。
staticな関数や変数、引数やマクロ名なんかには使えるけど、公開する関数名には使えない。

ほぼ全部やん!
残ってないやん!!
この項目の前に「標準ライブラリで」と書かれているので、何とか逃げようと思ったが、そんな無理はやめた方がよいだろう。

 

識別子の先頭として使える文字で"_"でないものを考えていたが、よいものがない。
VC++などであれば日本語のようなものも使えそうだが、どのコンパイラでもというのは難しいだろう。

うーん、アンダーラインのルールはもう少し緩くしてほしかったところだ。
2つはダメだけど、3つは使ってよい、とか。

実際のところ、アンダーラインで始まった名前を使ったとしても、コンパイルエラーになることはないだろう。
もしなったら、別の名前にすれば良いだけのことだ。
ただそれは、「車が通っていないから赤信号だけど渡ってしまおう」というのと同じで、問題はないけど割り切れない感じが残ってしまう。

 

私の模索は続く。。。

2017/03/07

[c/c++]static libraryで非static関数を隠すのは無理そうだ

2017/03/11 続編
[c/c++]static libraryでAPIを隠すのにもvisibility("hidden")が使えそう

ソースファイルが長くなってきたので、ファイル分割した。
長いと、スクロールするのが面倒なのでね。

そこまではよかったのだが、ファイル間で使いたい関数があった。
その関数は後悔するようなものではないのだが、ファイル間なので公開しないと使えない。
名前ルールで、いかにも公開してなさそうな名前にしても良いが、今後も出てくると思うので、コンパイラ依存で良いから解決できるのならやっておきたい。

 

こういうときは、オライリーのBinary Hacksだろうと眺めると、#29に載っていた。
載っていたのだが・・・これはshared libraryでのやり方だ。
__attribute__((visibility("hidden")))というやり方も書いてあったのだが、arでオブジェクトをまとめるだけではさすがに使えない。

まあねぇ。。。
リンクしないと、"hidden"といわれても、やってよいかどうかわからないだろう。

 

こちらに、詳しく説明があった。

http://stackoverflow.com/questions/22244428/hiding-symbol-names-in-library

うん、ダメなものはダメ、ということだ。

2017/03/06

[c/c++]最近gotoが多い

個人的な傾向なのだが、最近エラー処理でgotoを使うことが多くなってきた。

   ret = xxx_func();
   if (!ret) {
     goto FIN;
   }
   ...

FIN:
  return -1;
}

 

goto禁止というところも多いのだが、今は自分のルールでソースを書けるため、単に個人的な傾向なのだ。
私としては「gotoの乱用はよろしくないが、局所的ならいいんじゃないの」というスタンスでいる。
C++だとtry-catchという手段もあろうが、Cだとそういうものがないので、gotoで飛ばしているのだ。

 

しばらく前は、こういう書き方をしていた。
あ、retはboolと思っておくれ。

  ret = xxx_func();
  if (ret) {
     ret = yyy_func();
  }
  if (ret) {
    ret = zzz_func();
  }
  ...

こういう書き方をしたこともあった。
本か何かで見かけたのだと思う。

do {
  ret = xxx_func();
  if (!ret) {
    break;
  }
  ret = yyy_func();
  if (!ret) {
    break;
  }
  ...
} while (0);

 

まあ、どう書くにしても、

  • 戻り値を取得
  • 戻り値をif文でチェック
  • エラーだったら何かする

という処理を書くという点は同じだ。
その見せ方や流れが違うだけだろう。

 

do-while(0)はいいかな、と思っていたのだけど、トリッキーとまでは行かないが、ちょっと変則的な気もする。
だから、ifを連続して書くパターンを使うことが多かった。
最初のチェックでNGだったら、以降もずっとNGなのに、if文のチェックを全部やらないと処理を抜けられないので、なんだかなぁ、という気持ちはあったけど、まあ複雑になるわけでもないからよいか、と思っていた。

けれど、多重ループから抜けて終わらせたい、というパターンが出てきた。
内側のループと外側のループを抜けるためにどうするか?ということを考えているうちに、だんだん面倒になってきて、もうgotoで抜ければいいやん、になったのだろう。
そして、1箇所gotoで抜けたら、他もそのルールに合わせた方が自然な流れになるか、ということで、gotoを使うことが多くなったのだと思う。

 

最近使っているmbedTLSだと、その辺をマクロで隠蔽している。
MPI_CHK()みたいなマクロがあって、戻り値をretに代入し、0以外だったらgotoでcleanupラベルに飛ばしている。
だから呼び元では、

  • ret変数の宣言
  • cleanupラベルと、その後に後始末を書く

だけやっておけば、勝手にやってくれる(ように見える)。
他のOSでは、TRY-CATCHみたいなマクロを作っていて、それはlongjump()などを隠蔽していた記憶がある。

そういうマクロがあると、ソースはさっぱりして見えて良いのだけど、何をしているか知らずに使っていると思わぬ失敗をしてしまうこともあるので、気をつけたいところだ。

かといって、マクロを用意していなかったら、各人が好き勝手にエラー処理を書いて、それはそれで読みづらくなったり、エラー処理が漏れていたりすることもあるので、リズム良く書けるのであれば良いな、と思う。

2017/03/04

Makefileの:=

前回、Go言語の「:=」がshort variable declarationで、ブロック内なら型を書かずに使えるということがわかった。

 

そういえば、Makefileも「=」と「:=」の違いがあったが、なんだっただろうか?
Makefile における := と = の違い - Qiita
なるほど、中身を評価するタイミングが、「=」だと使うタイミングで、「:=」だと代入するタイミングということか。
「=」だと、結果じゃなくて式自体を保持しておかないといかんから、コストが高いのかな。

 

そういえば、JavaScriptで、タイミングの違いに注意という記事を見た記憶がある。
[Javascript] 関数宣言の落とし穴 function foo ( ){..} と var foo = function ( ) {..} は動作が違うので要注意! · DQNEO起業日記
すまぬ、わからんかった。。。

JavaScriptって、言語として難しく感じてしまう。
Pythonでスクリプト言語に多少慣れたから、そろそろいけるんじゃないかと思ったけど、ダメだった。
数年で1回くらいのペースでしか使わないのだけど、今月がそれなのよねぇ。。。

[golang][雰囲気]varがない変数らしきもの (2)

前回の続き。
変数っぽいけど、varしているところがファイル内にないが、なんなんだ?という疑問を持っていたのだが、これのようだ。

https://golang.org/ref/spec#Short_variable_declarations

「:=」を使うと、型宣言をせずに使えるらしい。
そうか、あのコロンにはそういう意味があったのか。。。
たまたま気がついた変数がそうだっただけで、他にも使われているわ。

同じブロック内か、パラメータリスト(引数のこと?)という制限はあるようだ。
「at least one of non-blank variables is new」とあるけど、これは何だろう。
nilがダメなのかと思ったが、untyped nilと怒られるので、それとは意味が違うのかもしれん。
(nilは検索するといろいろ出てきたので、今回は触れずにおこう。。。)

2017/03/03

[golang][雰囲気]varがない変数らしきもの (1)

なんとなくの知識で、Go言語で書かれたソースファイルを読んでいる。

 

読んでいるソースファイルで、

  • varが付いていないのに代入している
  • そのファイル内で何箇所も出てくる
  • ファイル内では、varが付いていない。

となっていたので、これはグローバル変数だろう、と当たりを付けた。
が、他のファイルを検索してもvarしている箇所がない。。。
MeteorでJavaScriptを書いていて、varを付けたり付け忘れたりで苦労しているのだが、Goもそういう言語なのだろうか?


宣言とスコープ
Declarations and scope

スコープ制御は、ブロックを使うとのこと。
ブロックは、{...}の中のことで、ここはCなどと同じようだ。
そして変数の宣言は、varが付く、となっている。
では、今回見つけたやつは、グローバル変数ではないし、そもそも変数ではないということか。

 

じゃあ、なんなのだ?
代入されて、メンバ関数を呼び出しているようなので、単なるエイリアスのような感じもする。
でも、Go言語のaliasは「alias type」みたいなので、typedef相当なのかも。

デバッグすれば分かると思うのだが、ソースだけで何とかしたいのだ。。。
時間がないので、次回に続きます。

[golang][雰囲気]スライス (2)

前回は、Go言語のスライス型だけ読んだ。
今回はスライスを読んで、終わりにしよう。

 

・・・あっさりした説明だった。


まずは、書いてあるとおりに実装してみよう。

01: package main
02: 
03: import "fmt"
04: 
05: func main() {
06:     a := [5]int{1, 2, 3, 4, 5}
07:     s := a[1:4]
08:     fmt.Printf("a=%s\n", a)
09:     fmt.Printf("s=%s\n", s)
10: }

結果

a=[%!s(int=1) %!s(int=2) %!s(int=3) %!s(int=4) %!s(int=5)]
s=[%!s(int=2) %!s(int=3) %!s(int=4)]

 

%sは「文字列またはスライスそのまま」らしい。
じゃあ、配列を%sで出力できると言うことは、配列もまたスライスに属するということだろうか。

いや、そもそも%sで文字列もスライスも配列も出力できるということは、%sは連続したメモリ領域を要素型に向けた出力形式で掃き出す、という意味を持つということか。
Cだと配列の要素数はsizeofでしかわからないし、文字列は\0で終わるというルールなので、こういうことはできなかったのだよな。

あ・・・・出力に「!」が入っているのは、エラーなのか。
つまり、エラーだけど出力してやったよ、ということなのか?
検索すると、%vというものがあるらしいので、変更して動かした。

a=[1 2 3 4 5]
s=[2 3 4]

うん、こっちの方が素直な出力だ。
ちなみに、%#vにするとこうなった。

a=[5]int{1, 2, 3, 4, 5}
s=[]int{2, 3, 4}

 

では、%sでスライスを出力できるというのは、なんなのだ?
英語版を見たけど、「the uninterpreted bytes of the string or slice」となっているので、

(the uninterpreted bytes of the string) || (slice)

だと読み取っているのだけど、もしかしたら、

the uninterpreted bytes of (the string || slice)

なのだろうか?

Google翻訳:「文字列またはスライスの解釈されていないバイト」
excite翻訳:「ストリングまたはスライスの解釈されていないバイト」
weblio英語翻訳:「ひもまたはスライスの解釈されてないバイト」
golang.jp:「文字列またはスライスそのまま」

うーん、こうやって並べると、or条件は「文字列かスライス」で、それにuninterpreted bytesがかかるというのが有力なのか。

では、私が最初に思ったように、orがスライスだけになるような文章はどういう書き方なのだろうか。

Google翻訳:「文字列の解釈されていないバイトまたはスライス」→uninterpreted byte or slice of string

えー、なんか違う気がする。。。
念のため、スライスをご飯にしてみよう。

Google翻訳:「文字列の解釈されていないバイトかライス」→uninterpreted byte or rice of string
Google翻訳:「文字列の解釈されていないバイトかご飯」→byte or rice not interpreted as a string

だんだん、何をしたかったのか分からなくなってきた。。

英語は、対象物を一番最後に置くような言語だったと思う。
SVCなり、SVOCなり。
だから、修飾する言葉が前にあって、その後ろにorで並んでいたら、その修飾はorしている両方にかかるということか。
もし、私が思ったように一部だけかかるようにしたいなら、orがまだ前に来るように並べるか、コンマで区切るとか、そういう対策をするんじゃなかろうか。

 

では、最初の疑問に戻って、%sだ。
Printf()で!が出力されるのはエラーということだが、%sでスライスを与えてもエラーになった。
では、%sで出力される文字列ではないスライスというのは、どういうものなのだろうか?

英語版の方では、%vを使った場合に、要素型に対応するフォーマットが書かれている。
%vでint型を表示しようとしたら、それは%dになりますよ、というような対応だ。
そこにはsliceが書かれていない。
もしかしたら、%sのsliceは、文字列のslice、つまり部分文字列を指しているだけなのだろうか?

 

また何か分かるのかもしれんが、集中してsliceのことを調べるのはここまでにしよう。

2017/03/02

[golang][雰囲気]スライス (1)

お仕事で、Go言語のソースを読もうとしている。
書こうとしている、ではない。
読むだけだ。

もちろん、読み書きできるのが一番良いし、望ましいのだが、いかんせん時間が無い。
あちこち目をつぶって、雰囲気だけつかむことを目指す。


その第1弾が、スライスだ。

 

スライス型
http://golang.jp/go_spec#Slice_types

スライス
http://golang.jp/go_spec#Slices

スライスは「ある配列内の連続した領域への参照」と書いてある。
そしてスライス型は「その要素型と同じ要素型を持つ配列のすべてのスライスの集合」らしい。

なぜ配列とは別になっているのだろうか?
配列内で、連続した領域を参照しているなら、それはそれで配列なんじゃなかろうか。。。

いま思っているのは、太枠が配列だとしたら、赤い部分がその一部を参照しているうスライスだ。
スライスは要素が0から始まると書いてあるので、こうなるはず。

image

 

 

スライス型の1項目前が「配列型」だった。
http://golang.jp/go_spec#Array_types
配列も型なんだ・・・。
説明だけ読むと、配列型は要素型の要素を複数持っていて、インデックスで連番アクセスできて、長さも持っている、というだけのようだ。
他の言語と同じように見える。
まあ、C/C++の配列は要素数を持たないけどね。

 

スライスは、キャパシティ、という概念があるようだ。
ちょっと違うが、STLのsize()とcapacity()みたいな雰囲気がある。
上の図だと、capacityは5になるはず。

 

make()で新しいスライスを作ることができるらしい。
・・・ん?
makeの引数に、要素型と長さの指定、capacityまで指定はできるけど、そもそも参照型だから「誰のどこから」という情報がいるんじゃなかろうか。
「隠された配列を新たに割り当て」など、参照するという言葉の意味が分からなくなってくる。。。
新しい領域を割り当てるんだったら、それはもう配列でよいんじゃないのか??

 

まだスライス型のところを読んだだけなので、次の「スライス」を読むと謎が解決するのかもしれない。
ともかく、今回はここまで。