アセンブリのお勉強

以下では、Intel syntax に従います。また、CPU は 16bit とします。

1.Move Instruction (Transfer Instruction)

1-1.Unconditional Move Instruction

move.asm

  mov destination, source ;transfer source to destination

1-2.Conditional Move Instruction

cmoveとcmovz、cmovneとcmovnzのマシーンコードは同じです。

cmove.asm

  cmove  destination, source ;zf == 1 → transfer source to destination
  cmovne destination, source ;zf == 0 → transfer source to destination

1-3.PUSH Instruction and POP Instruction

PUSH命令及びPOP命令は、転送命令の一つです。

〈PUSH命令の流れ〉
0)PUSH命令の実行前にインストラクションポインタが命令長分だけインクリメンする。(PUSH命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)PUSH命令が実行されると、スタックに格納するデータのサイズ(operand-size attribute)だけスタックポインタが減算される。
2)スタックポインタが指す位置にデータが格納される。

〈POP命令の流れ〉
0)POP命令の実行前にインストラクションポインタが命令長分だけインクリメンする。(POP命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)POP命令が実行されると、スタックポインタが指す位置から格納先のサイズだけデータが取り出される。
2)スタックから取り出されたデータのサイズ(operand-size attribute)だけスタックポインタが加算される。

push.asm

  push source     ;transfer source to [sp]
  pop destination ;transfer [sp] to destination

1-4.I/O Instruction

I/O命令は、転送命令の一つです。

io.asm

  in destination, (port address) ;transfer [port address] to destination
  out (port address), source     ;transfer source to [port address]


2.Compare Instruction

compare.asm

  cmp ax, 0
  cmp ax, bx
  cmp ax, [0x0000]
  cmp source1, source2

  ZF CF
source1 < source2 0 1
source1 == source2 1 0
source1 > source2 0 0


<Equality Comparator XNOR>
X XNOR Y ≡ (X∧Y)∨(¬X∧¬Y)


3.Jump Instruction (Branch Instruction)

ジャンプ命令は、インストラクションポインタ(ip)への転送命令です。

3-1.Unconditional Jump Instruction

jump.asm

  jmp source ;set source to ip

3-2.Conditional Jump Instruction

jeとjz、jneとjnzのマシーンコードは同じです。

cjump.asm

  je  source ;zf == 1 → set source to ip
  jne source ;zf == 0 → set source to ip

jcxz は、cx が 0 でなければ何もせず、cx が 0 になればオペランドにジャンプします。

jcxz.asm

start:
  mov cx 10

loop:
  ・・・・・・・
  inc cx
  jcxz break ;cx == 0 → jump to break
  jmp loop:

break:
  ・・・・・・・

3-3.Unconditional Loop Instruction with Count Register

loop は、cx をディクリメントした後、cx が 0 でなければオペランドにジャンプし、cx が 0 になればループを抜けます。

loop.asm

  loop source ;cx--, cx != 0 → set source to ip

loop1.asm

start:
  mov cx 10

label:
  ・・・・・・・
  loop label

  ・・・・・・・

3-4.Conditional Loop Instruction with Count Register

loopeとloopz、loopneとloopnzのマシーンコードは同じです。

cloop.asm

  loope  source ;cx--, cx != 0 and zf == 1 → set source to ip
  loopne source ;cx--, cx != 0 and zf == 0 → set source to ip

3-5.CALL Instruction and RET Instruction

CALL命令及びRET命令は、ジャンプ命令の一つです。

〈CALL命令の流れ〉
0)CALL命令の実行前にインストラクションポインタが命令長分だけインクリメンする。(CALL命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)CALL命令が実行されると、インストラクションポインタの値がスタックに転送される。(インストラクションポインタがプッシュされる)
2)呼び出し先のアドレス(CALL命令のオペランド)がインストラクションポインタにセットされる。

〈RET命令の流れ〉
0)RET命令の実行前にインストラクションポインタが命令長分だけインクリメンする。(RET命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)RET命令が実行されると、スタックの値がインストラクションポインタに転送される。(インストラクションポインタにポップされる)

call1.asm

start:
  call sub1
  call sub2

sub1:
  push ax
  push bx
  push cx
  ・・・・・・・
  pop cx
  pop bx
  pop ax
  ret

sub2:
  pusha
  ・・・・・・・
  popa
  ret

スタックを使ってサブルーチンに値を渡す。

call2.asm

main:
  push 3 ;sp-=2
  push 2 ;sp-=2
  push 1 ;sp-=2
  call addxyz ;sp-=2

addxyz:
  push bp ;sp-=2
  mov bp, sp
  mov ax, [bp+4]
  add ax, [bp+6]
  add ax, [bp+8]
  mov sp, bp
  pop bp
  ret

call2.c

short addxyz(short x, short y, short z) {
  return x + y + z;
}

int main(void) {
  addxyz(1, 2, 3);
}

3-6.Software Interrupt Instruction

ソフトウェア割り込み命令は、ジャンプ命令の一つです。INT命令及びIRET命令は、それぞれCALL命令及びRET命令に対応しています。

int.asm

  int (interrupt number)
  int 0x21 ;DOS System Call
  int 0x80 ;Linux System Call
  iret


4.Other Instructions

4-1.Increment Instruction and Decrement Instruction

increment.asm

  inc state ;state + 1 → state
  dec state ;state - 1 → state

4-2.Arithmetic Instruction

arithmetic.asm

  add state, source ;state + source → state
  sub state, source ;state - source → state
  mul state, source ;state * source → state
  div state, source ;state / source → state

4-3.Logic Instruction

logic.asm

  not state         ;¬ state → state
  and state, source ;state ∧ source → state
  or  state, source ;state ∨ source → state

4-4.Bit Manipulation Instruction (Bit Shift Instruction and Bit Rotate Instruction)

bitmanipulation.asm

  shl state, count
  shr state, count
  rol state, count
  ror state, count

4-5.No Operation Instruction and Halt Instruction

nop.asm

  nop
  hlt


参考サイト

1.x86 Assembly
2.Assembly Programming
3.x86 Instruction Set Reference
4.NASM (Netwide Assembler)
5.Central Processing Unit instructions set
6.アセンブリ言語の基礎知識
7.アセンブリ言語の基礎知識 Part5
8.x86アセンブリ言語での関数コール
9.ARM Instruction Sets
10.Conditional Move Instructions
11.CMP命令とフラグの変化
12.比較命令とジャンプ命令
13.Jump and Branch Instructions
14.LOOP/LOOPcc
15.Bit Shift and Rotate Instructions
16.新・コンピュータ解体新書
17.独習アセンブラ

V850のタイマー割り込み

組み込み勉強中です!下記のプログラムに間違いがあればアドバイス願います!
INTTP0CC0は、1msのタイマー割り込み要求でいいのかな?
どこかでインターバルの設定をするのかな?

volatileは、レジスタを参照する変数や割り込みハンドラ(interrupt handler)と通常の関数(normal function)で共有される変数(下記の例では、counter_10msやcounter_20ms)などを修飾するために用いられ、コンパイル時に最適化を抑止するそうです。

timer_interrupt.h

#ifndef TIMER_INTERRUPT_H
#define TIMER_INTERRUPT_H

//extern volatile unsigned int counter_10ms;
//extern volatile unsigned int counter_20ms;
extern void function_10ms(void);
extern void function_20ms(void);

#endif

timer_interrupt.c

/* V850 */

static volatile unsigned int counter_10ms;
static volatile unsigned int counter_20ms;

//1msのタイマー割り込み要求(INTTP0CC0)で割り込みハンドラ(handler_1ms)を呼び出す設定
#pragma interrupt INTTP0CC0 handler_1ms

//1ms毎に呼び出される割り込みハンドラ
__interrupt void handler_1ms(void) {
  counter_10ms++;
  counter_20ms++;
}

//10ms毎に実行される通常の関数
void function_10ms(void) {
  if (counter_10ms >= 10) {
    //procedure_10ms();
    counter_10ms = 0;
  }
}

//20ms毎に実行される通常の関数
void function_20ms(void) {
  if (counter_20ms >= 20) {
    //procedure_20ms();
    counter_20ms = 0;
  }
}

main.c

#include "timer_interrupt.h"

void main(void) {
  for (;;) {
    function_10ms();
    function_20ms();
  }
}


参考サイト

1.V850 ファミリ
2.タイマ機能を使ったプログラミング
3.V850ES/Jx3 サンプルプログラム(割り込み)
4.V850 割り込みサンプルプログラム
5.V850 サンプルプログラム1
6.V850 サンプルプログラム2
7.Google:V850 割り込み

Bitwise Operator and Logical Operator

・Bitwise AND Operator & と Logical AND Operator &&

C/C++の論理演算(logical operation)では、0は偽(false)、0以外は真(true)です!

and.c

#include <math.h>
#include <stdio.h>

int main(void) {
  printf("%d\n", 0&1);
  printf("%d\n", 2&3);
  printf("%d\n", 0&&1);
  printf("%d\n", 2&&3);
  printf("%d\n", 'a'&&"abc");

  int i = 3;
  int n = 7;
  if ((int)pow(2, i - 1) & n) {
    printf("The %d-th bit in the binary representation of the decimal number %d is 1!\n", i, n);
  }
  else {
    printf("The %d-th bit in the binary representation of the decimal number %d is 0!\n", i, n);
  }
}

〈実行結果〉

0
2
0
1
1
The 3-th bit in the binary representation of the decimal number 7 is 1!


参考サイト

1.Google:Bitwise Operator and Logical Operator
2.2進数、8進数、10進数、16進数相互変換ツール

C/C++における条件コンパイル

条件コンパイル(conditional compilation)のやり方です。日本語では、コンパイラスウィッチとかコンパイルスウィッチと呼ばれることがあります。

conditional_compilation1.c

#include <stdio.h>
#define DEBUG 1

int main(void) {
#if DEBUG
  printf("Debug Mode!\n");
#endif
}

conditional_compilation2.c

#include <stdio.h>
#define DEBUG

int main(void) {
#ifdef DEBUG
  printf("Debug Mode!\n");
#endif
}


参考サイト

1.#ifディレクティブを使った条件コンパイル
2.#ifdefディレクティブを使った条件コンパイル

inurlを使ったサイト内検索

Googleのinurl(URLに含まれる文字列)を使ったサイト内検索方法です。

search.htm

<html>
<body>
<form action="http://www.google.com/search" target="_blank">
<input type="hidden" name="hl" value="ja">
<input type="text" name="hq" value="inurl" size="50">
<input type="text" name="q" value="keyword" size="50">
<input type="submit" value="search">
</form>
</body>
</html>

〈使い方〉

一つ目のテキストフィールドにinurlを入力し、二つ目のテキストフィールドに検索したいキーワードを入力します。


参考サイト

1.サイト内の検索にGoogle.comを使う方法

FLTK による GUI アプリケーションの開発(Windows)

FLTK は超軽量クロスプラットフォームのGUIライブラリです。ライブラリが静的にリンクされるので FLTK がインストールされていない Windows PC でも実行できます。その上、生成される実行ファイルのサイズが小さいので容易に配布できます。また、プログラムを比較的簡単に作成できるのもメリットの一つです。
ということで、私はとても気に入っています!
以下では、Windows環境での FLTK による GUI アプリケーションの作成手順について説明します。


1.MinGW と MSYS のインストール

FLTK をビルドするために、MinGW をDドライブの直下にインストールします。インストールの際に MinGW Installation Manager で mingw32-gcc-g++msys-base を指定すると MSYS も一緒にインストールできます。MinGW のインストールについては、“clang++ による DLL のビルド” の記事の MinGW の箇所を参考にして下さい。
インストールが終わったら、D:\MinGW\msys\1.0\msys.bat をダブルクリックして MSYS を起動し、下記のコマンドを実行するとパスを設定できます。
注)exit で一旦終了して MSYS を再起動した後にパスが有効になるので、exit するのを忘れないで下さい。

<MSYS>

$ echo "PATH=\$PATH:/D/MinGW/bin" > .profile
$ exit


2.FLTK のビルドとインストール

まず、FLTK のソールファイル fltk-1.3.3-source.tar.gz をダウンロードし、
“D:\MinGW\msys\1.0\home\ユーザ名”の直下に置きます。
続いて、D:\MinGW\msys\1.0\msys.bat をダブルクリックして MSYS を起動し、ソースファイルのあるディレクトリで以下のコマンドを実行すれば、解凍 → ビルド → インストール が行えます。

<MSYS>

$ tar -xvf fltk-1.3.3-source.tar.gz
$ cd fltk-1.3.3
$ ./configure
$ make
$ make install


3.C++によるプログラムの作成

以下は、FLTK を使ったサンプルプログラムです。

fltk1.cpp

#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Window.H>

auto copy(Fl_Widget* widget, void* v) -> void {
  const char* input = ((Fl_Input*)((void**)v)[0])->value();
  ((Fl_Output*)((void**)v)[1])->value(input);
}

auto main() -> int {
  Fl_Window* window = new Fl_Window(500, 200, "^o^");
  window->begin();
  Fl_Button* button = new Fl_Button(0, 0, 50, 25, "copy");
  Fl_Input* input = new Fl_Input(50, 50, 250, 25, "input:");
  Fl_Output* output = new Fl_Output(50, 100, 250, 25, "output:");
  window->end();
  void* v[] = {input, output};
  button->callback(copy, v);
  window->show();
  return Fl::run();
}

fltk2.cpp

#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Window.H>

auto copy(Fl_Widget* widget, void* v) -> void {
  const char* input = ((Fl_Input*)(widget->parent()->child(1)))->value();
  ((Fl_Output*)(widget->parent()->child(2)))->value(input);
}

auto main() -> int {
  Fl_Window* window = new Fl_Window(500, 200, "^o^");
  window->begin();
  Fl_Button* button = new Fl_Button(0, 0, 50, 25, "copy");
  Fl_Input* input = new Fl_Input(50, 50, 250, 25, "input:");
  Fl_Output* output = new Fl_Output(50, 100, 250, 25, "output:");
  window->end();
  button->callback(copy);
  window->show();
  return Fl::run();
}

fltk3.cpp

#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Window.H>

class CopyWindow : Fl_Window {
  Fl_Button* button;
  Fl_Input* input;
  Fl_Output* output;
public:
  CopyWindow(int, int, const char*);
private:
  static auto copy(Fl_Widget*, void*) -> void;
};

CopyWindow::CopyWindow(int width, int height, const char* title) : Fl_Window(width, height, title) {
  begin();
  button = new Fl_Button(0, 0, 50, 25, "copy");
  input = new Fl_Input(50, 50, 250, 25, "input:");
  output = new Fl_Output(50, 100, 250, 25, "output:");
  end();
  button->callback(copy, this);
  show();
}

auto CopyWindow::copy(Fl_Widget* widget, void* v) -> void {
  ((CopyWindow*)v)->output->value(((CopyWindow*)v)->input->value());
}

auto main() -> int {
  CopyWindow copyWindow(500, 200, "^o^");
  return Fl::run();
}

drag and drop.cpp

#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Window.H>

auto split(const std::string& input, char delimiter) -> std::vector<std::string> {
  std::istringstream istringstream(input);
  std::string buffer;
  std::vector<std::string> output;
  while (std::getline(istringstream, buffer, delimiter)) {
    output.push_back(buffer);
  }
  return output;
}

class EventBox : Fl_Box {
public:
  EventBox(int x, int y, int width, int height);
private:
  auto handle(int event) -> int;
};

EventBox::EventBox(int x, int y, int width, int height) : Fl_Box(FL_UP_BOX, x, y, width, height, "") {
  label("Hello!");
  labelcolor(FL_BLUE);
  labelfont(FL_ITALIC);
  labelsize(50);
}

auto EventBox::handle(int event) -> int {
  std::ofstream ofstream;
  switch (event) {
    case FL_DND_DRAG:
    case FL_DND_ENTER:
    case FL_DND_RELEASE:
      return 1;
    case FL_PASTE:
      label("Love!");
      labelcolor(FL_RED);
      ofstream.open("fout.txt");
      ofstream << split(Fl::event_text(), '\n')[0];
      ofstream << std::flush;
      ofstream.close();
      return 1;
    default:
      return Fl_Box::handle(event);
  }
}

auto main() -> int {
  Fl_Window window(200, 100, "^o^");
  EventBox eventBox(0, 0, 200, 100);
  window.show();
  return Fl::run();
}


4.プログラムのビルド

MSYSで以下のコマンドを実行するとプログラムをビルドできます。
注)-static を外すと、実行する際に libstdc++-6.dll と libgcc_s_dw2-1.dll が必要になります。

<MSYS>

$ g++ -std=c++11 -static `fltk-config --cxxflags` fltk.cpp `fltk-config --ldflags` -o fltk.exe
$ strip fltk.exe


参考サイト

1.FLTK
2.FLTKとは
3.Beginner FLTK Tutorial
4.Compile FLTK with g++
5.Erco’s FLTK Cheat Page
6.3-Common Widgets and Attributes
7.C++ FLTK BUTTONS TUTORIAL
8.Simple Inherited Window
9.Complex FLTK Window
10.FLTK で GUI を使ってみる
11.C/C++のGUIライブラリ比較
12.MinGW+MSYSのインストール
13.MinGW (64bit) + MSYS 環境の構築(1)
14.tarのオプションをまとめる
15.FOX toolkit のメモ

C++におけるクラス内配列

クラス内配列を添字演算子[](index operator, subscript operator)のオーバーロードを利用して記述します。


1.クラス内で配列を静的に確保する

C/C++では配列そのものを関数の引数や戻り値にすることはできませんが、以下のArrayクラスではそれが可能です。これを使えば複数の値の値渡しや値戻しができます。関数の引数や戻り値がベクトルである場合に使うと便利です。もちろん、配列長が大きい場合は参照渡しや参照戻しを使うこともできます。

array1.cpp

#include <cassert>
#include <iostream>

template <int LENGTH> class Array {
  double array[LENGTH];
public:
  const int length = LENGTH;
  Array() {
    if (length > 0) {
      for (int i = 0; i < length; i++) {
        array[i] = 0;
      }
    }
  }
  Array& operator=(const Array& object) {
    if (length > 0) {
      for (int i = 0; i < length; i++) {
        array[i] = object.array[i];
      }
    }
    return *this;
  }
  double& operator[](int index) {
    assert(0 <= index && index < length);
    return array[index];
  }
  const double& operator[](int index) const {
    assert(0 <= index && index < length);
    return array[index];
  }
};

Array<10> echo1(Array<10> array) {
  return array;
}

const Array<10>& echo2(const Array<10>& array) {
  return array;
}

int main() {
  const int length = 10;
  //Array<length> array;
  auto array = Array<length>();
  for (int i = 0; i < array.length; i++) {
    array[i] = i;
  }
  auto array1 = Array<length>();
  array1 = array;
  for (int i = 0; i < array1.length; i++) {
    std::cout << array1[i] << std::endl;
  }
  for (int i = 0; i < echo1(array).length; i++) {
    std::cout << echo1(array)[i] << std::endl;
  }
  for (int i = 0; i < echo2(array).length; i++) {
    std::cout << echo2(array)[i] << std::endl;
  }
}

array2.cpp

#include <cassert>
#include <iostream>

template <int LENGTH> class Array {
  double array[LENGTH];
public:
  const int length = LENGTH;
  Array();
  Array& operator=(const Array&);
  double& operator[](int);
  const double& operator[](int) const;
};

template <int LENGTH> Array<LENGTH>::Array() {
  if (length > 0) {
    for (int i = 0; i < length; i++) {
      array[i] = 0;
    }
  }
}

template <int LENGTH> Array<LENGTH>& Array<LENGTH>::operator=(const Array& object) {
  if (length > 0) {
    for (int i = 0; i < length; i++) {
      array[i] = object.array[i];
    }
  }
  return *this;
}

template <int LENGTH> double& Array<LENGTH>::operator[](int index) {
  assert(0 <= index && index < length);
  return array[index];
}

template <int LENGTH> const double& Array<LENGTH>::operator[](int index) const {
  assert(0 <= index && index < length);
  return array[index];
}

Array<10> echo1(Array<10> array) {
  return array;
}

const Array<10>& echo2(const Array<10>& array) {
  return array;
}

int main() {
  const int length = 10;
  //Array<length> array;
  auto array = Array<length>();
  for (int i = 0; i < array.length; i++) {
    array[i] = i;
  }
  auto array1 = Array<length>();
  array1 = array;
  for (int i = 0; i < array1.length; i++) {
    std::cout << array1[i] << std::endl;
  }
  for (int i = 0; i < echo1(array).length; i++) {
    std::cout << echo1(array)[i] << std::endl;
  }
  for (int i = 0; i < echo2(array).length; i++) {
    std::cout << echo2(array)[i] << std::endl;
  }
}


2.クラス内で配列を動的に確保する

スタックに格納できないサイズの配列を扱う際に使うと便利です。また、ディストラクタが自動で動的に確保した配列の後始末をしてくれます。

注)オブジェクトの値渡しでは、値渡しの際にコピーコンストラクタが呼び出され、関数を抜ける時にディストラクタが呼び出されます。

注)メンバ変数にポインタがあるオブジェクトの値渡しでは、関数を抜ける時に呼び出されるディストラクタがコピー元の実体を解放するので、値渡しの際に実体がコピーされるようにコピーコンストラクタを定義しておきます。

array3.cpp

#include <cassert>
#include <iostream>

class Array {
  double* array;
public:
  int length;
  Array(int length) : array(NULL), length(length) {
    if (length > 0) {
      array = new double[length];
      for (int i = 0; i < length; i++) {
        array[i] = 0;
      }
    }
  }
  Array(const Array& object) : array(NULL), length(object.length) {
    if (length > 0) {
      array = new double[length];
      for (int i = 0; i < length; i++) {
        array[i] = object.array[i];
      }
    }
  }
  Array& operator=(const Array& object) {
    array = NULL;
    length = object.length;
    if (length > 0) {
      array = new double[length];
      for (int i = 0; i < length; i++) {
        array[i] = object.array[i];
      }
    }
    return *this;
  }
  ~Array() {
    if (array != NULL) {
      delete[] array;
      array = NULL;
    }
  }
  double& operator[](int index) {
    assert(0 <= index && index < length);
    return array[index];
  }
  const double& operator[](int index) const {
    assert(0 <= index && index < length);
    return array[index];
  }
};

Array echo1(Array array) {
  return array;
}

const Array& echo2(const Array& array) {
  return array;
}

int main() {
  int length = 10;
  //Array array(length);
  auto array = Array(length);
  for (int i = 0; i < array.length; i++) {
    array[i] = i;
  }
  auto array1 = Array(length);
  array1 = array;
  for (int i = 0; i < array1.length; i++) {
    std::cout << array1[i] << std::endl;
  }
  for (int i = 0; i < echo1(array).length; i++) {
    std::cout << echo1(array)[i] << std::endl;
  }
  for (int i = 0; i < echo2(array).length; i++) {
    std::cout << echo2(array)[i] << std::endl;
  }
}

array4.cpp

#include <cassert>
#include <iostream>

class Array {
  double* array;
public:
  int length;
  Array(int);
  Array(const Array&);
  Array& operator=(const Array&);
  ~Array();
  double& operator[](int);
  const double& operator[](int) const;
};

Array::Array(int length) : array(NULL), length(length) {
  if (length > 0) {
    array = new double[length];
    for (int i = 0; i < length; i++) {
      array[i] = 0;
    }
  }
}

Array::Array(const Array& object) : array(NULL), length(object.length) {
  if (length > 0) {
    array = new double[length];
    for (int i = 0; i < length; i++) {
      array[i] = object.array[i];
    }
  }
}

Array& Array::operator=(const Array& object) {
  array = NULL;
  length = object.length;
  if (length > 0) {
    array = new double[length];
    for (int i = 0; i < length; i++) {
      array[i] = object.array[i];
    }
  }
  return *this;
}

Array::~Array() {
  if (array != NULL) {
    delete[] array;
    array = NULL;
  }
}

double& Array::operator[](int index) {
  assert(0 <= index && index < length);
  return array[index];
}

const double& Array::operator[](int index) const {
  assert(0 <= index && index < length);
  return array[index];
}

Array echo1(Array array) {
  return array;
}

const Array& echo2(const Array& array) {
  return array;
}

int main() {
  int length = 10;
  //Array array(length);
  auto array = Array(length);
  for (int i = 0; i < array.length; i++) {
    array[i] = i;
  }
  auto array1 = Array(length);
  array1 = array;
  for (int i = 0; i < array1.length; i++) {
    std::cout << array1[i] << std::endl;
  }
  for (int i = 0; i < echo1(array).length; i++) {
    std::cout << echo1(array)[i] << std::endl;
  }
  for (int i = 0; i < echo2(array).length; i++) {
    std::cout << echo2(array)[i] << std::endl;
  }
}


参考サイト

1.演算子のオーバーロード
2.subscript operator overloading
3.Overloading the C++ indexing subscript operator []
4.Overloading the Subscript Operator [] the Right Way
5.クラス内での配列の動的確保
6.関数とオブジェクト
7.オブジェクト利用時の注意点
8.迷信:new に失敗すると NULL が返る?
9.コピーコンストラクタ、代入演算子、デストラクタ(The Law of The Big Three)
10.コピー操作と参照