K3の住民

最近レア社のことをほとんど書いていない自称レア社好きがゲームやプログラミングについて色々書いていく。

JavaScriptで学ぶCの構造体

一応PC・スマホも「機械」と定義されているので、「PCでプログラムを動かす=機械
を動かす」という意味で機械カテゴリだけを入れていましたが、今度から
プログラミング関係の記事は新しく追加するプログラミングカテゴリも入れていこう
と思います。

皆さん、お久しぶりです。あけましておめでとうございます(遅)。雪圀です。
今回はゲーム記事じゃなくてプログラミングに関する記事を書いていこうと思い
ます。


JavaScriptにはCの構造体の概念がありませんが、とてもよく似た記述があるので
それを通してCにも触れるきっかけにもなれば、と思います。
何故JavaScriptを選んだのかっていうと、JavaScriptは使われることの多い言語で
あるかつ、ダウンロードの必要が無く手っ取り早く始めやすい言語であるから
です(ダウンロードをすれば始められるJavaPHPでやっても良かったけど)。

データ型

JavaScriptでは「var (変数名)」で整数や文字列などなんでも宣言できますが、Cだと
整数は「int (変数名)」、文字列は「char *(変数名)」などのように宣言する必要
があります。例を挙げるとこんな感じです。

JavaScript
C
var val = 0;
int val = 0;
var str = "abc";
char *str = "abc";

構造体とは

構造体は、複数の値を格納できるデータ型の一種で、複数の値は異なるデータ型で
格納することが出来ます。こいつをJavaScriptで説明してみます。
先ず、JavaScriptでは関数をオブジェクト型として扱うことが出来、「new (関数
名)」とすることでオブジェクトのインスタンスを生成することが出来ます。
では、人物を示す関数human()を使い、meオブジェクトのインスタンスを生成して
みます。

// 人物
function human(name, age)
{
  this.name = name;  // 人物の名前
  this.age = age;     // 人物の年齢
}


// 人物「yukiguni」とその年齢
var me = new human("yukiguni", 65535);


// コンソール出力用
var msg = "Name: " + me.name + "\nAge: " + me.age;


// コンソールに人物の名前と年齢を出力
console.log(msg);

human()関数にnameプロパティとageプロパティの値に引数を代入し定義したことで、
「var me = new human("yukiguni", 65535);」とすると、

me.name = "yukiguni";
me.age = 65535;

としたことと同義となります。msgに名前と年齢を分かりやすく表示するメッセージ
を入れ、「conole.log(msg);」でコンソールにmsgを出力します。だから最終的には
コンソールに以下のメッセージが出力されるはずです。

Name: yukiguni
Age: 65535

これ、Cでも似たようなコードで書くことが可能なんですね。
では、Cで表してみます。

#include <stdio.h>


int main(void)
{
  // 人物
  typedef struct
  {
    char *name;       // 人物の名前
    unsigned int age;   // 人物の年齢
  } human_t;
  
  // 人物「yukiguni」とその年齢
  human_t me = { "yukiguni", 65535 };
  
  // コンソールに人物の名前と年齢を出力
  printf("Name: %s\nAge: %d", me.name, me.age);
  
  return 0;
}

これがCによる構造体の例です。
JavaScriptではオブジェクト型で定義された変数をプロパティと呼んでいましたが、
Cではstructというデータ型で宣言し、そこにさらに複数の変数を宣言していきます。
このとき宣言される変数を、メンバと呼びます。
JavaScriptで書いたオブジェクト型と、Cで書いた構造体を比較してみます。

JavaScript
C
function human(name, age)
{
  this.name = name;
  this.age = age;
}
typedef struct
{
  char *name;
  unsigned int age;
} human_t;

どこか似てると思いません?

次にJavaScriptではオブジェクトのインスタンスを生成したと思いますが、Cでは
宣言した構造体はデータ型として使用出来、今回の例であればhuman_t型の変数の
宣言が出来るようになります。
では、JavaScriptのオブジェクトのインスタンスの生成とCのhuman_t型変数の宣言を
比較してみましょう。

JavaScript
C
var me = new human("yukiguni", 65535); human_t me = { "yukiguni", 65535 };

わざと似せるように書いたのでこれらもどこか似ているのでは無いかと思います。

最後にJavaScriptのオブジェクトとCの構造体の違い、ですね。JavaScriptのオブジェ
クトではプロパティだけで無く、メソッドの定義も出来ますが、Cでは出来ません。
また、JavaScriptのオブジェクトではインスタンスを生成した後も、新たなプロパティ
やメソッドを定義することが出来ます。Cで新しく作ったデータ型で宣言後新しい
メンバを宣言するなんてことをやっちゃうとコンパイラに怒られちゃいます。

余談(typedefの話)

因みにstructの前にtypedefがついていたと思います。あれは、構造体や既存のデータ
型を別の名前に置き換える役割を担っています。
例えば、「typedef unsigned int uint_t;」と書けば、uint_t型の宣言はunsigned int型で
宣言することと同じになります。
何故構造体を使う場合にtypedefが必要なのかというと、例えば以下の例のように
human型を作ったとします。

struct human
{
  char *name;
  unsigned int age;
};

このとき、そのデータ型を宣言するにはいちいち「struct human」とつけて宣言
しなければなりません。
それは流石に面倒くさい!ってことで、構造体はタグと呼ばれるものがあるのです
が(さっきの場合タグ名は「human」)、それを無しにし、タグなし構造体を別の
名前に置き換えることで、いちいちstructとつけずに型名だけで宣言出来るように
なります。
今回やった例の場合、「struct { ... }」を「human_t」に置き換えています。
typedefを使って置き換えたデータ型の名前は最後に「_t」をつけるのが一般的で
あり、この「_t」があることで「typedefを使って置き換えた名前ですよ」って
ことを示しています。


以上です。疲れた・・・。
本当は共用体もやりたかったですが、JavaScriptで共用体と同じ役割のコードを
作るのが難しそうだと思ったので今日は構造体だけにしました。
JavaScript初心者なのでCの構造体には自信がありますけど、JavaScriptのオブジェ
クトには正直あまり自信が無いです。
だから指摘(JavaScriptだけで無くCも)はどんどんしていってください。

今回はこれくらいにしときます。