Xcode -aggeragate target-

ところで、であるが、アイキャッチの赤い三重丸のようなやつの正式名称を知っているだろうか?

aggeregate target

どことなく射的の的を連想させるアイコン(ターゲット)は aggeregate というらしい。

英単語としての発音は「アーグリゲイト」、一般的な意味は「集約する、合計する」だ。

日本語の情報はほとんどなく

ライブラリ・SDKにSwiftLintを導入するベストプラクティス

でかろうじて触れられているのみ。

aggregate target を生成するのもややクセがあって、

File -> New -> Target…

として(↓)、

ダイアログを表示させ iOS や macOS ではなく other の方を選ぶ。

これは調べないと分かりませんね。

参考

その他、Xcode やビルドシステムについて。

・cmake 単体で iOS のプロジェクトを取り扱う。

cmakeを使ってxcodeを使わずにiosアプリを作成する

・cmake で Xcode のプロジェクトファイルを生成する。

CMakeとIDEを連携させる

help によれば cmake で framework を直接生成できるらしいのだが、試したことはない。
(→結局、試しました

余談 -External Build System-

ところで、アーグリゲイトなターゲットを作成する際、こういう画面が出てくる。

気になるのは External Build Sysytem だと思うが、イマイチ使い方がわからない。

デフォルトだと make を使うように設定されているのだが、aggregate ターゲットでもいけるはずだが???

余裕があったら、調べます。

余談 Xcode での C++ 標準ライブラリのヘッダーファイルの置き場所

Xcode14 では

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1

です。

よく移動になるみたいですね。

標準ライブラリのヘッダーファイルが見つからない場合は、上のフォルダを header search paths に設定する。

 

OpenJPEG を使ってみる

他のライブラリに組み込まれて使われることの多い OpenJPEG というライブラリだが、opj_compress や opj_decompress というコマンドラインツールもあるらしい。

さあ、これを使おうと思ったのだが、インストール時にやらかしていたようです…orz

これは再インストールですな。

libpng について

普通にインストールすれば(↓)、png.framework はできないはずだが、はて?

おそらく、インストールの過程のどこかで png.framework を生成していたんでしょう。

ところで libpng にもコマンドラインツールがあるようだ。
興味がある方は、ターミナルから libpng16-config とタイプしてください。

再インストール

libpng → OpenJPEG の順にインスコ。
再度、コマンドラインツールを呼び出すと…

% opj_decompress -h

This is the opj_decompress utility from the OpenJPEG project.
It decompresses JPEG 2000 codestreams to various image formats.
It has been compiled against openjp2 library v2.5.0.

Parameters:
-----------

  -ImgDir <directory> 
	Image file Directory path 
  -OutFor <PBM|PGM|PPM|PNM|PAM|PGX|PNG|BMP|TIF|TIFF|RAW|YUV|RAWL|TGA>
    REQUIRED only if -ImgDir is used
	Output format for decompressed images.

今度は、正常に起動。

テスト

テストコマンドが使えるようになったので、png ファイルで圧縮・伸展を試してみる。

今回は特にオプションをいじらず、ノーマルのまま。

結果は以下のようになった。

ちょっと色目が濃くなっている感じでしょうか。

医療画像

ところで、JPEG 2000 は当初の想定よりは普及している感じはしないが(それでも MacOS では標準でサポートされている)、医療画像の世界では広く使われているようだ。

この記事内で

日頃お世話になっている DCMTK だが、JPEG2000 系は(オープンソース版)では基本的にはサポート外だ。

内部的には OpenJPEG 組み込んでいるはずなんですけどね(すっとぼけ)。

と言及されている。

DCMTK と OpenJPEG の橋渡しは、いろいろな方法が考えられると思うが(上の例のように OpenJPEG のアプリで圧縮・展開ができているのだから、これを組み込んだソフトでできないはずがない)、自分で繋ぎのコードを書いてもいいし、このプロジェクトを使ってもいいだろう。

後者のプロジェクトは CMake の書き方があまりいいものではないので、MacOS なら .xcodeproj を生成させてからビルドするといいと思う。

 

覚え書きとものぐさ

プログラミング関係の記事が増えてきた。

読み返すとタイトルに「ものぐさ」あるいは「覚え書き」とついているものが多い。

今まで厳密に使い分けてきたわけではなかったが、

ものぐさ・・通常、難解とされているところを肩に力が抜けた感じで、さらっと書く

覚え書き・・基本的なことをある程度実用的にまとめる

というような傾向があるようだ。

今後はこの方針である程度意識的にタイトルつけていきやす。

 

C/C++ 覚え書き -ポインタ-

やはり「C/C++ は難しい」という声をよく聞く。

実際、最近、twitter でこんなやりとりがあった。

ワイも極めるレベルまではいってないが、まあ困らない程度には使える。
古今東西の C で書かれたライブラリを使うために悪戦苦闘しているうちに何となく覚えてしまった。

C/C++ の習得を難しくしている原因の一つは、ポインタだろう。

ポインタの基本

twitter でも書いたが、ポインタの簡単なサンプルを上げておくとこんな感じか。

//test.c
#include <stdio.h>

int main(){

    //int *a;
    int* a;

    int b=100;

    a = &b;

    printf("%d", *a);

}

これをコンパイルする。素直にコンパイルするなら、こんな感じか。

gcc -o test test.c

これで test という実行可能なファイルができる。
実行させると、もちろん

100

と表示される。

わざわざ

int *a

も書いておいたのは、こう書いても結果は変わらないから。
ただ、こう書くと初学者の理解はがこんと悪くなるという印象を持っている。

なんで、ここでわからなくなるかといえば、おそらく、宣言時の *a と最後の printf で( a で差し示されている)実際の数値を表示させる *a を混同してしまうからだと思う。

ポインタ変数といえども変数には変わりなく、宣言が必要だ。もちろん、型も必要。

上の場合は、int 型のポインタ変数 a を宣言したいのだから、int* と書いた方が(少なくとも初学者にとっては)混乱は減ると思う。
あくまで変数としては a なのだから。

通常の変数と違うのは、ここにアドレスが格納されるという特殊性だろう。

a 自体はアドレスなのだから、その(アドレスで示されている)実体を知りたければ何らかの操作が必要で、シンプルに * をつける。
* は宣言時にも使われるので、両者を混同してしまうのだろう。

次の難所 -文字列と配列-

ポインタの概念が分かってもそれだけでは使えないと思う。

これはおそらく C の配列や文字列の扱いのせいでしょう。
取り扱いというか約束事ね。

配列

上のようなプリミティブな数値型の場合、ポインタを使いたければ * を使えばよかったが、配列も同じようにするとうまくいかない。

つまり

int[] *a;

という表現はしない
というかする必要がない。

というのは、C では、配列 array[] などと書いた場合、array つまり配列変数名自体はその先頭要素へのポインタになっているからだ。

サンプルコードを示すと以下のようになる。

#include <stdio.h>

int main()
{
    //int[] *p;
    
    int array[]={1,2};
    
    printf("%d",*array);
    
    return(0);

}

結果は 1 。
int[] *p という宣言は、エラーになる。

ところで、こういう書き方は、近年の配列に要素数が簡単に追加できたり型推論してくれたりする言語に慣れた人からすると、奇異に映るようだ。
奇異というか不安に近い感情だろうか。

array に要素を追加したい場合、どうするんですか?と。

安心して欲しい。C では、原則、要素数の追加はできない
(C での可変長配列に関してはここらあたりの記事参照)

なお、この場合、配列 array の要素数を知りたければ、以下のようななんとも面倒くさい書き方になる。
こちらのオンライン C コンパイラーサイトを使用)

array 自体のメモリサイズを sizeof で求めて、それを要素のバイト数で割って、ようやく要素数を知ることができる。

このコードにしても unsigned 絡みでワーニング出てますけどね。

ついでで言っておくと C/C++ ではファイルサイズを調べるときも(直接これを調べるような関数のようなものは提供されていないので)同様に若干手間のかかるアプローチを取る必要がある。

このツィなど参照。

大きさを調べるときには注意が必要

なお、(初学者は絶対混乱すると思うが)array[] という書き方と *array という書き方は C コード内で厳密にはまったく同じ挙動をするわけではない。

よく知られた例としては、sizeof(*array) とするとポインタの大きさを返すのみで、array 自体の大きさを返しているわけではない

バグの原因となる。

ちょっと実用的なサンプル -バイナリファイルを 2byte 毎に読み込む-

ここら辺の仕様はややこしいところだが、実務的には便利なときがある。

あるバイナリファイルがあった時、これをバイト配列ではなく、2byte や 4byte の数値配列として読み込みたいということがよくある。
C++ になってしまうが、以下のようなコードはよくお目にかかる。

    const char* fname="(PathTo)/sample.raw";
    std::ifstream ifs(fname, std::ios::binary);
    ifs.seekg(0,std::ios::end);
    uint64_t size = ifs.tellg();
    ifs.seekg(0);

    uint16_t *data16 = new uint16_t[size/2];
    ifs.read((char*)data16,size);

このコードのキモは

ifs.read((char*)data16,size)

だ。
ifstream::read() は、仕様的にはバイト配列しか読み込めないが、2byte 配列 data16 のポインタをバイト配列のポインタでキャストすることで 2byte の配列として読み込んでくれる。

いったん、バイト配列として読み込んだ後、2byte の配列にマッピングし直して・・・という複雑な処理は必要ない

これをやるためには、ファイル自体の大きさ(バイト数)を予め知っておく必要があるが、その処理は前段で行なっている。ファイルの大きさ一つとってもこういう書き方をする。

なお、このコードの意味を理解したときはいたく感動した。

ポインタが使われている例としてよく知られたものだが、もう一つ例示しておくと main(argc, *argv[]) の意味もわかってみるとなんということはない。

こちらの記事あたり参照。

配列を舐めてはいけない

ところで、ポインタの話をすると、そこだけに注力してしまい、その他の知識が疎かになりやすい。

ポインタと配列の関連が深いのは上でも述べたが、実用的なプログラミングでは両方の知識を絡ませないとにっちもさっちもいかない。

C の配列で知っておかなければいけない知識は、

配列は初期化しないと使えない

という(ポインタに比べるとあまり注意を払われないんだが)超重要仕様。意外に理解してない人が多い。

初期化には、最初から全てを代入するとか初期化子を使う方法とかいくつかやり方があるんだが、最近のワイの好みは memset などを使って、根こそぎメモリ領域を確保しておく方法。

uint16_t testarray[100];
memset(testarray, 0, sizeof(uint16_t)*100);

あるいは(ややこしいが、こちらの方が実用的)、

uint16_t *testarray = (uint16_t *)calloc(100, sizeof(uint16_t));
// any code you want
free(testarray);

これで全ての要素に 0 が入るので、この初期化以降は testarray[50] だのに好きな値を代入できる。

もちろん、C の配列の使い方(可変長が許されない&初期化する必要がある)は、不便を感じることが多く、例えば MacOS/iOS のアプリを作成する際には、配列のみで攻めていく、ということはないと思う。

なお、最近、実感しているのは、NSData の優秀性。

長さが不定な重要データは NSData 型で管理し、具体的な処理は C ライブラリに任せるとかやると混乱は減る。

「ポインタ」は重要だが、ポインタだけじゃダメって話です。

参考:『配列を自由自在に作る』など。
C で配列が使いにくい→ malloc などで対応、という流れが簡潔に説明されている。
malloc + memset = calloc という感覚なのだが、具体例が出たときにでも追記したい。
こちらの記事もいい。

最初はピンとこないかもしれないが

配列[変数]

となっている配列を扱いたいときにここら辺の知識があやふやだと、うまく扱えない。

逆に「C 使えるようになってきたかな?」と実感できるのはここら辺の知識が身についてきたとき。

Xcode プロジェクトで C/C++ でファイル入出力を扱うとき

アップルの話が出てきたので、ついでに。。。

最近、プライベートでは Mac 使う場合が多いが、これ(↓)知ってないとハマるかも。

デフォでは、ファイルアクセスに制限がある

BAD_ACCESS 関係のエラーが出たら、設定を見直しておきましょう。

参考

C 言語における 16 進表記文字列⇄バイナリ列変換』この配列操作はしばしば話題になるが、これで決定かな。
magicarray を使ったロジックが美しい。

 

C++ 感覚を取り戻す

IT 業界でフリーでやっている若い世代は、仕事を選べる立場にある人はそんなに多くはないと思う。

そんな時に C++ 案件が舞い込んでくると、意外に基礎がすっぽりと抜けてたりする。

そういうわけで急いで C++ 感覚を取り戻すためのメモ。

ワイの場合、Objective-C や Qt も扱っているので、この変更が意外に手間かかったりする。
「似ているようで違う」というのは、思っている以上にタチ悪いかも(笑)。

ハロワ

あまり C++ っぽくはないが、まあ基礎。

//hello.cpp
#include <iostream>

int main(){
    std::cout << "hello world";
}

ソース自体は C とあまり変わらない。

が、コンパイルは

g++ -o hello hello.cpp

または

clang++ -o hello hello.cpp

とする。
gcc や clang では、c と解釈するのかエラーになる。

 

(続く。『江添 C++ 本と本家ストラウストラップ本』あたりもご参考に)