2014-01-01から1年間の記事一覧
static int s1 = 0x7fffffff; static int s2 = 0x12345678; int main(int argc, char **argv) { s1 = 0x7f7f7f7f; s2 = 0x87654321; return 0; } .symtabは、シンボルに関する属性情報(そのシンボルがメモリ上に実体を持つセクションのセクション番号と、当…
処理系による。 型 数学的値 内部表現 汎整数拡張後 char -1 0xFF 0xFFFFFFFF unsigned char 255 0xFF 0x000000FF int -1 0xFFFFFFFF − unsigned int 4294967295 0xFFFFFFFF − 比較関係 左辺↓右辺→ (char)-1 (unsigned char)255 (int)-1 (unsigned int)42949…
個人的メモです。データ型モデル 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かを判定するマクロを作成してみました。 #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>…
ついに来ました、ビットシフト。みんな大好きビットシフト。signed型の負数に対する右ビットシフトの結果は処理系依存なので、以下の話はgcc限定ととらえて下さい。まずは、unsigned char型のビットシフトから。 unsigned型のビットシフトは解説するところが…
整数型の値に対して、その下位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)>
汎整数拡張、俗にいう「暗黙のキャスト」はソースコードに出てこないところの挙動なので、C言語上級者でもなかなかに引っかかりやすいトラップだと思います。先日、組込み系の記事で見かけた例ですが…以下コードは、unsigned char型変数をビット反転し、その…
前回は、以下のことを確認しました。 基本形が同じならば、signed/unsigendでキャストしようが、その内部表現(ビット列)は変化しない。 内部表現が同じであっても、その数学的値が同じとは限らない。 今回は、char/unsigned charをint/unsigned intにそれ…
「C言語はポインタが難しい」というのが定説ですが、ポインタは四天王の中でも最弱だと思っています。ポインタ以上に難解なのが、この「汎整数拡張」。インテグラル・プロモーション(integral promotion)とも言います。汎整数拡張の挙動を確認する上で、ビ…
「詳説Cポインタ」p43より。 2.2.1 malloc関数の使い方 (略) void* malloc(size_t); malloc関数はsize_t型の引数を1つ取ります。この型は1章で扱いました。引数に値を指定する際には、 注意が必要です。負の値を指定した場合には、問題となります。システ…
配列の添字指定は「人間にとっての分かりやすい表現」であって、配列概念など知ったこっちゃない処理系は「ベースアドレス(先頭要素へのポインタ値)+要素サイズ*要素番号」という計算式で、配列の各要素にアクセスしているのです。配列が「先頭要素へのポ…
ポインタ・配列についての「分かりやすい説明」を目指すことは、ネットの解説でも多くみかけますが、ポインタと配列は、根本的に日常とはかけ離れたアクロバティックな頭の使い方を求められるので、日常的直観との距離を縮める比喩的説明(住所を書いたメモ…
頭の体操として、二次元配列の各要素を参照するコードを、いろんな書き方で書いてみようと思います。いまさら二次元配列?と思うなかれ。こういう当たり前のコードを、1ステップずつ意味を理解した上で、高速でコーディングできるのも、ひとつの技術力だと思…
関数の引数に配列型変数を指定した場合、関数内の当該仮引数はポインタ型変数に型調整される(正確には、配列の先頭要素へのポインタ値が格納されたポインタ型変数に型調整される)。これが多次元配列になると、どうなるだろう。二次元配列とは、T型配列のT…
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の計算に影響を与えない数式の場合、式自体が翻訳時に捨てられているのが分かります。 00000000004004e3 <main>: i</main>…
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ファイルのコメント行・空行をスキップし、コメント部を削除して、各レコードを配列に格納するスクリプトです。 ・行"aaa,bbb ccc,ddd"を分割して、2列目の値「bbb ccc」がスペースで区切られないこと。←これは対応したが ・"aaa,,ccc"で、「ccc」が3列目…
awkを使った、テキストファイルを処理するスクリプトです。csvファイル(sample.csv)から1行ずつ読み込み、そのフィールド数を標準出力する。 行頭の直後が行末である行は空行とする。 (半角スペースまたはタブ文字)のみで構成された行は空行とする。 行…
シェルで扱うコマンドの終了コードは、その指定可能な値の範囲は8ビットの整数である。終了コードは、特殊変数「$?」にセットされる。負の整数を指定することも可能だが、その場合、当該値を2の補数表現として解釈した値が「$?」にセットされる。その場合の…
サブシェルとは、以下のサンプルコードで言うと、4〜7行目にわたって「()」で括られたリストを指します。「シェルスクリプトを実行する」とは、シェルが新たなシェルを子プロセスとしてメモリ上にロードし、その子プロセスが引数に指定されたスクリプトフ…
セグメントディスクリプタのリニアアドレスの算出式を疑似コードで表現すると、 QWORD segment_desc segment_desc := *(QWORD *)((gdtr AND 0xFFFFFFFF0000) + (segment_reg AND 0xFFF8))上で求めたセグメントディスクリプタの値(segment_desc)から、飛び…
Linuxカーネルは、4GBのアドレス空間上の「0xC0100000」にロードされます。これはおおよそ3Gの位置ですが、「0xC0100000 = 0xC0000000 + 0x100000」なので、正確には「3G+1M」の位置にロードされることになります。論理アドレス上では上記の通りですが、物理…
63 56 55 54 53 52 51 48 47 46 44 43 41 40 39 32 +----------------+---+---+---+---+--------------------+---+---+---+------+---+-------------------+ |ベース(上位8bit)| G | D |res|AVL| リミット(上位4bit) | P |DPL| S |タイプ| A | ベース(中8ビ…
セグメント・セレクタとは、ディスクリプタ・テーブル上、現在どのディスクリプタを使用しているかを示す「セレクタ値」のことです。セレクタ値は、セグメント・レジスタに格納されます。 15 3 2 1 0 +---------------+--+---+ | Index |TI|RPL| +----------…
GDTRについて。 GDTR(Global Descriptor Table Register)とは、論理アドレス→物理アドレスのマッピングテーブルの先頭アドレスを格納するレジスタである。 47 16 15 0 +---------------------+-------------+ | Linear Base Address | Table Limit | +----…