C言語」タグアーカイブ

「関数の副作用の有無」よりも大事なもの

プログラミングをやっていると、「関数に副作用がある」とか「副作用がない」あるいは「純粋である」という話をちょいちょい耳にする。そして、「外界の状態を読み取るけど変更はしない関数」、例えば

function getTime() {    return Date.now();}

のような関数に副作用があるか?みたいな議論が始まったりする。

くだらない議論だ。

何か概念を定義するときは、それが「役に立つ」場面を提示できる必要がある。「関数の副作用」を定義するときは、「関数の副作用」がわかったときに何をしたいのかをはっきりさせる必要がある。「関数のどういう側面に注目したいか」を決めずに「副作用の有無」を論じるのはナンセンスだ。

ここでは、言語処理系(コンパイラー)を実装する者の立場で、関数の副作用について論じてみたい。

続きを読む

never型があると便利か(言語処理系実装者の観点から)

TypeScriptをはじめとするいくつかのプログラミング言語には、never型という型がある。この型は典型的には「制御を返さない関数」の返り値として使われる:

function f(x: string): never {    console.error(x);    throw new Error();}

never型は型システム的には「値を持たない型」「任意の型の部分型」として特徴づけられる。

他のプログラミング言語、例えば私が作っているLunarMLにもnever型があると便利だろうか?

続きを読む

浮動小数点数の指数部と仮数部への分解とその逆:logbとscalbn

浮動小数点数は指数部と仮数部の積で表される。

続きを読む

C言語でクロージャーを実現したい、あるいは実行時のコード生成によるクロージャー

導入:クロージャーについて

昨今ではクロージャーを使えるプログラミング言語は珍しくなくなった。クロージャーとは、関数の引数だけではなく、外のスコープにある変数を参照できる関数のことである。

例えば、次のJavaScriptコードでは、関数を返す関数f を定義している。f の中で定義された無名関数は、外側の変数x を参照できている。

function f(x) {    return function(y) {        return x + y;    };}

JavaScriptではネストした関数を使わなくても、bindメソッドによって同等の処理を記述することができる:

function g(x, y) {    return x + y;}function f(x) {    return g.bind(null, x); // gの第1引数を束縛する}

残念ながらC言語にはクロージャーはない。関数の中に関数を書けないからだ。

しかし、クロージャーと同等のこと、つまり関数に追加の引数を渡すことはできないのだろうか?

続きを読む

C言語のワイド文字入出力 — Windows Console 編

前回の記事では、主に相手がファイルの場合を扱った。今回は、 Windows のコンソールに対して MSVCRT の入出力関数を使う場合を考える。続きを読む

C言語のワイド文字入出力 — MSVCRTの場合

前回はC言語の標準規格の話と glibc の実装を取り上げたが、今回は Visual C++ のランタイムライブラリである MSVCRT を取り上げる。MSVCRT は Visual C++ でコンパイルしたプログラムだけではなく、 MinGW でも使われる。続きを読む

C言語のワイド文字入出力

C言語にはワイド文字で入出力を行う関数が用意されている。

※ワイド文字:C言語のワイド文字 (wchar_t) とは、不憫な子である。Windows だと Unicode のコードポイント1個すら表せない16ビットだったり、Unix だとそもそも使われている気配があまりなかったり(もっぱら UTF-8 か UTF-16 が使われている印象がある)する。2010年代の後半にもなってワイド文字なんぞを真面目に扱うブログというのは時代錯誤も甚だしい。

ワイド文字で入出力と言っても、対象がファイルの場合は最終的にはバイト列を読み書きしているわけで、どこかの段階でバイト列とワイド文字列との変換が行われているはずである。この変換方法はどうやって決まっているのか。あるいは、ワイド文字の入出力関数とバイト列 (char) の入出力関数を混在させるとどうなるのか。

また、Visual C++ や glibc の場合は fopen の第2引数に,ccs=UTF-8 みたいな文字列を設定できるという謎の仕様がある。これを指定した場合は何が UTF-8 になるのか。

こういった細かい仕様は、ワイド文字自体がオワコンなこともあり、あまり知られていないように思う。少なくとも筆者は知らなかった。というわけで、

  • ワイド文字による入出力について、C言語の規格ではどう定められているか
  • Visual C++ のランタイムライブラリ (MSVCRT) ではどう実装されているか
  • Linux 等で使われている glibc ではどう実装されているか
  • macOS 等で使われている BSD libc ではどう実装されているか

の4点について調べた。(ただし、 MSVCRT については別の記事に分割する)続きを読む

浮動小数点数による複素数の演算に関する注意点

コンピューターで複素数を表す時は、通常は実部と虚部の組をそれぞれ浮動小数点数として持つ。

複素数の演算は、数学的には続きを読む

Visual C++ での C99 complex

最近のVisual C++ではC99もある程度サポートしているらしい。

上記ブログによると、 complex.h の関数もサポートしているらしい。しかし、コンパイラーは_Complex 型をサポートしていない。_Complex 型をサポートしていないのに、 complex.h の関数をサポートしているとはどういうことか。一体、 complex.h の関数は何を受け取って何を返すのか。

確認のため、次のような簡単なC++ のプログラムを書いてみた。続きを読む

C言語でなんちゃって2進数リテラル

こういうビットマップ(1ピクセルにつき1ビット)を、整数の配列としてC言語のソースコード中に埋め込みたい:

□□□□□■■■■■□■□■□□■□■□■□□■■□□□□□

2進数リテラルがあればそれを使うという手があるが、残念ながらC言語には2進数リテラルがない(ちなみに、C++にはC++14から2進数リテラルが入った。また、独自拡張で2進数リテラルが使えるコンパイラーもある)。

というわけで、自分で作ることにした。要件としては

  • コンパイル時定数となる
  • 桁を空白で区切れる

がある。続きを読む