2014-06-01から1ヶ月間の記事一覧

データ型モデル・規格Cごとの接尾語なし10進定数の型の違い

個人的メモです。データ型モデル char short int long long long void * ILP32 8 16 32 32 64 64 LP64 8 16 32 64 64 64 規格Cごとの接尾語なしの10進定数の型について。 以下のうち、その定数がオーバーフローしないような最小の型が選ばれる*1。 C89 int, …

オペランドのsigned/unsigned判定マクロ

算術変換の検証をする上で、対象の整数値がsignedかunsignedかを判定するマクロを作成してみました。 #define <limits.h> #define IS_SIGNED(x) ( \ (( (x)>>1)&(1L<<(sizeof(x)*CHAR_BIT-1)))!= \ ((~(x)>>1)&(1L<<(sizeof(x)*CHAR_BIT-1))) ) というものです。このマ</limits.h>…

【汎整数拡張】第5回 算術シフトと論理シフト

ついに来ました、ビットシフト。みんな大好きビットシフト。signed型の負数に対する右ビットシフトの結果は処理系依存なので、以下の話はgcc限定ととらえて下さい。まずは、unsigned char型のビットシフトから。 unsigned型のビットシフトは解説するところが…

【汎整数拡張】第4回 (2^n)による剰余とビットマスク(2^n)-1によるAND演算に等価性はあるか

整数型の値に対して、その下位nビットを取り出す場合、 x & ((1<<n)-1) と書いたりしますが、これって2を法とする剰余(2^nで割った余り)でも表現できないか?と考えたことはあると思います。まず、char/unsigned char型変数の値127に対して、(2^n)-1でマスクをかけてみます。 > char : 127 0111 1111 > char -> int 0000 0000 0000 0000 0000 0000 0111 1111 > c & 0x0F 0000 0000 0000 0000 0000 0000 0000 1111 > unsigned char : …</n)-1)>

【汎整数拡張】第3回 汎整数拡張の意外な落とし穴

汎整数拡張、俗にいう「暗黙のキャスト」はソースコードに出てこないところの挙動なので、C言語上級者でもなかなかに引っかかりやすいトラップだと思います。先日、組込み系の記事で見かけた例ですが…以下コードは、unsigned char型変数をビット反転し、その…

【汎整数拡張】第2回 単項変換

前回は、以下のことを確認しました。 基本形が同じならば、signed/unsigendでキャストしようが、その内部表現(ビット列)は変化しない。 内部表現が同じであっても、その数学的値が同じとは限らない。 今回は、char/unsigned charをint/unsigned intにそれ…

【汎整数拡張】第1回 内部表現と数学的値

「C言語はポインタが難しい」というのが定説ですが、ポインタは四天王の中でも最弱だと思っています。ポインタ以上に難解なのが、この「汎整数拡張」。インテグラル・プロモーション(integral promotion)とも言います。汎整数拡張の挙動を確認する上で、ビ…

malloc(3)に負の値を渡すと

「詳説Cポインタ」p43より。 2.2.1 malloc関数の使い方 (略) void* malloc(size_t); malloc関数はsize_t型の引数を1つ取ります。この型は1章で扱いました。引数に値を指定する際には、 注意が必要です。負の値を指定した場合には、問題となります。システ…

配列とは結局こういうこと

配列の添字指定は「人間にとっての分かりやすい表現」であって、配列概念など知ったこっちゃない処理系は「ベースアドレス(先頭要素へのポインタ値)+要素サイズ*要素番号」という計算式で、配列の各要素にアクセスしているのです。配列が「先頭要素へのポ…

ポインタについて語ってみた

ポインタ・配列についての「分かりやすい説明」を目指すことは、ネットの解説でも多くみかけますが、ポインタと配列は、根本的に日常とはかけ離れたアクロバティックな頭の使い方を求められるので、日常的直観との距離を縮める比喩的説明(住所を書いたメモ…

二次元配列をダンプする

頭の体操として、二次元配列の各要素を参照するコードを、いろんな書き方で書いてみようと思います。いまさら二次元配列?と思うなかれ。こういう当たり前のコードを、1ステップずつ意味を理解した上で、高速でコーディングできるのも、ひとつの技術力だと思…

sizeof演算子のまとめ(仮引数の多次元配列)

関数の引数に配列型変数を指定した場合、関数内の当該仮引数はポインタ型変数に型調整される(正確には、配列の先頭要素へのポインタ値が格納されたポインタ型変数に型調整される)。これが多次元配列になると、どうなるだろう。二次元配列とは、T型配列のT…

sizeof演算子のまとめ(配列の型調整)

sizeof演算子の続きです。 関数のプロトタイプ宣言で配列型を指定された引数は、関数の仮引数ではポインタ型として扱われる、というお話です。 1 /* sizeof_func.c */ 2 #include <stdio.h> 3 4 void func(char buf[]){ 5 printf("sizeof(buf)@func = %zu\n", sizeof(</stdio.h>…

sizeof演算子のまとめ

sizeof演算子について、いろいろ試してみました。アセンブリコードを見てみると、sizeofオペランドの式はコンパイル時に定数に置換されるか、sizeofの計算に影響を与えない数式の場合、式自体が翻訳時に捨てられているのが分かります。 00000000004004e3 <main>: i</main>…

5.1 プロセスID

Linuxではカーネルがinitを起動する際、以下の順番でパス検索し、はじめに見つかったinitを起動する。 /sbin/init /etc/init /bin/init /bin/sh initのPIDは1。 PIDの最大値は32768(/proc/sys/kernel/pid_max)。 PIDの割当ては単調増加方式で、サイクリッ…

標準出力バッファリング

例えば、1秒ごとに「.」(ドット)を表示するプログレスバー的なものを考えてみます。 1 /* progress.c */ 2 #include <stdio.h> 3 #include <unistd.h> 4 5 int main(int argc, char *argv[]) 6 { 7 int i; 8 9 for(i=0; i<10; i++){ 10 printf("."); 11 sleep(1); 12 } 13 14 </unistd.h></stdio.h>…

csvの空行・コメント行・コメント部分を除外して、配列に格納する

CSVファイルのコメント行・空行をスキップし、コメント部を削除して、各レコードを配列に格納するスクリプトです。 ・行"aaa,bbb ccc,ddd"を分割して、2列目の値「bbb ccc」がスペースで区切られないこと。←これは対応したが ・"aaa,,ccc"で、「ccc」が3列目…