Javaによるオブジェクト指向プログラミング
Javaのクラスは参照型(reference type)です。
注)Javaのローカル変数は、明示的に初期化しなければなりません。
注)Javaのメンバー変数は、明示的に初期化しなくても暗黙的にデフォルト値(default value)で初期化されます。
class Robot {
private double x, y;
Robot() {
set(0, 0);
}
Robot(double x, double y) {
set(x, y);
}
void set(double x, double y) {
this.x = x;
this.y = y;
}
double getX() {
return x;
}
double getY() {
return y;
}
void move(double dx, double dy) {
x += dx;
y += dy;
}
void print() {
System.out.println("x = " + x);
System.out.println("y = " + y);
}
}
class Main {
public static void main(String... args) {
Robot robot1 = new Robot();
robot1.move(1, 1);
robot1.print();
System.out.println("x = " + robot1.getX());
System.out.println("y = " + robot1.getY());
Robot[] robot2 = new Robot[]{new Robot(), new Robot()};
for (Robot robot : robot2) {
robot.move(1, 1);
robot.print();
}
int n = 10;
Robot[] robot3 = new Robot[n];
for (int i = 0; i < robot3.length; i++) {
robot3[i] = new Robot(0, 0);
robot3[i].move(i, i);
robot3[i].print();
}
}
}
コンパイル
set JAVA_HOME=D:\sdk\jdk set path=%path%;%JAVA_HOME%\bin javac *.java
実行
set JAVA_HOME=D:\sdk\jdk set path=%path%;%JAVA_HOME%\bin java Main pause
継承
class Position {
double x, y;
Position() {
set(0, 0);
}
Position(double x, double y) {
set(x, y);
}
void set(double x, double y) {
this.x = x;
this.y = y;
}
}
class Robot extends Position {
Robot() {
super();
}
Robot(double x, double y) {
super(x, y);
}
}
class Main {
public static void main(String... args) {
Robot robot0 = new Robot();
System.out.println("x = " + robot0.x);
System.out.println("y = " + robot0.y);
Robot robot1 = new Robot(1, 1);
System.out.println("x = " + robot1.x);
System.out.println("y = " + robot1.y);
}
}
packageの作成とimport
packageの作成
package pkg1.pkg2.pkg3;
public class Hello {
public Hello() {
System.out.println("Hello!");
}
}
packageのコンパイル
set JAVA_HOME=D:\sdk\jdk set path=%path%;%JAVA_HOME%\bin javac D:/pkg/pkg1/pkg2/pkg3/*.java
JARライブラリの作成
set JAVA_HOME=D:\sdk\jdk set path=%path%;%JAVA_HOME%\bin jar cfv lib.jar pkg1
注)jar cfv lib.jar D:/pkg/pkg1 とするとうまくいきません!
Mainクラスの作成(packageのインポート)
import pkg1.pkg2.pkg3.Hello;
class Main {
public static void main(String... args) {
new Hello();
//new pkg1.pkg2.pkg3.Hello();
}
}
Mainクラスのコンパイル
set JAVA_HOME=D:\sdk\jdk set path=%path%;%JAVA_HOME%\bin javac -cp D:/pkg *.java
Mainクラスの実行
set JAVA_HOME=D:\sdk\jdk set path=%path%;%JAVA_HOME%\bin java -cp .;D:/pkg Main pause
Mainクラスのコンパイル(JARライブラリを使った場合)
set JAVA_HOME=D:\sdk\jdk set path=%path%;%JAVA_HOME%\bin javac -cp D:/pkg/lib.jar *.java
Mainクラスの実行(JARライブラリを使った場合)
set JAVA_HOME=D:\sdk\jdk set path=%path%;%JAVA_HOME%\bin java -cp .;D:/pkg/lib.jar Main pause
access modifier | same class | same package | subclasses in other package | from anywhere |
---|---|---|---|---|
public | ○ | ○ | ○ | ○ |
protected | ○ | ○ | ○ | × |
no modifier | ○ | ○ | × | × |
private | ○ | × | × | × |
参考サイト
- Controlling Access to Members of a Class
- Access modifiers in java - Javatpoint
- Access Modifiers in Java
- jarファイルを作成しよう
- JARライブラリの作成と利用
C++によるオブジェクト指向プログラミング
コンストラクタはオブジェクトの記憶領域が確保された直後に実行され、ディストラクタはオブジェクトの記憶領域が解放された直後に実行されます。どちらも自動的に実行されます。また、コンストラクタの中で変数を new した場合は、通常ディストラクタの中でその変数を delete します。
注)C++では構造体もクラスも値型(value type)です。
注)A a; クラスAのデフォルトコンストラクタが定義されていれば、aはデフォルトコンストラクタで初期化されます。
注)デフォルト引数(default parameter)のデフォルト値(default value)は、関数のプロトタイプ宣言で設定します。
注)デフォルトコンストラクタとは、引数がないか、全ての引数にデフォルト値が設定されているコンストラクタです。
注)引数無しのコンストラクタと全ての引数がデフォルト引数であるコンストラクタを同時に定義するとエラーになります。
注)static const の整数型メンバー変数を除いて、メンバー変数を宣言と同時に初期化しないこと! → 初期化してもよい!
オブジェクトの初期化と代入
注)C++では初期化の=と代入の=の違いに注意する必要があります。
#include <iostream>
class Robot {
public:
double x = 1, y = 1;
};
int main() {
Robot robot;
std::cout << robot.x << std::endl;
std::cout << robot.y << std::endl;
}
#include <iostream>
class Robot {
double x, y;
public:
Robot();
Robot(double, double);
void set(double, double);
double getX() const;
double getY() const;
};
//メンバー初期化リストを使った引数無しコンストラクタ&デフォルトコンストラクタ
//Robot::Robot() : x(0), y(0) {}
//引数無しコンストラクタ&デフォルトコンストラクタ
Robot::Robot() {
set(0, 0);
}
//メンバー初期化リストを使った引数付きコンストラクタ
//Robot::Robot(double x, double y) : x(x), y(y) {}
//引数付きコンストラクタ
Robot::Robot(double x, double y) {
set(x, y);
}
void Robot::set(double x, double y) {
this->x = x;
this->y = y;
}
double Robot::getX() const {
return x;
}
double Robot::getY() const {
return y;
}
int main() {
//デフォルトコンストラクタによる初期化
Robot robot;
std::cout << robot.getX() << std::endl;
std::cout << robot.getY() << std::endl;
//一時オブジェクトの代入
robot = Robot();
robot = Robot(0, 0);
//デフォルトコピーコンストラクタによる初期化
Robot robot0(robot);
//デフォルト代入演算子によるオブジェクトの代入
robot0 = robot;
//引数無しコンストラクタによる初期化
Robot robot1(); // -> NG
auto robot2 = Robot();
//引数付きコンストラクタによる初期化
Robot robot3(3, 3);
auto robot4 = Robot(4, 4);
}
#pragma once
#include <iostream>
class Robot {
double x, y;
public:
static int nRobots;
//default constructor with default parameters
Robot(double x = 0, double y = 0) : x(x), y(y) {}
Robot(const Robot& robot) {
x = robot.x;
y = robot.y;
}
Robot& operator=(const Robot& robot) {
x = robot.x;
y = robot.y;
return *this;
}
virtual ~Robot() {}
void set(double x, double y) {
this->x = x;
this->y = y;
}
double getX() const {
return x;
}
double getY() const {
return y;
}
void move(double dx, double dy) {
x += dx;
y += dy;
}
void print() const {
using namespace std;
cout << "(x, y) = " << "(" << x << ", " << y << ")" << endl;
}
};
int Robot::nRobots = 0;
#include "robot.hpp"
int main() {
//Robot robot0;
//Robot robot0(1);
//Robot robot0(1, 1);
auto robot0 = Robot();
robot0.print();
Robot robot1(robot0);
robot1 = robot0;
robot1.move(1, 1);
robot1.print();
auto robot2 = new Robot;
robot2->move(2, 2);
robot2->print();
delete robot2;
//g++ OK, clang++ NG
Robot::nRobots = 10;
Robot robot3[Robot::nRobots];
for (int i = 0; i < Robot::nRobots; i++) {
robot3[i].set(0, 0);
robot3[i].move(3, 3);
robot3[i].print();
}
Robot::nRobots = 10;
auto robot4 = new Robot[Robot::nRobots];
for (int i = 0; i < Robot::nRobots; i++) {
robot4[i].set(0, 0);
robot4[i].move(4, 4);
robot4[i].print();
}
delete[] robot4;
}
set path=d:\sdk\msys64\mingw64\bin;%path%; g++ -std=c++17 -O3 -pedantic-errors -s -Wall -static *.cpp -o main.exe strip main.exe
#pragma once
class Robot {
double x, y;
public:
static int nRobots;
Robot(double x = 0, double y = 0);
Robot(const Robot&);
Robot& operator=(const Robot&);
virtual ~Robot();
void set(double, double);
double getX() const;
double getY() const;
void move(double, double);
void print() const;
};
#include "robot.hpp"
#include <iostream>
int Robot::nRobots = 0;
/* member initialization list
Robot::Robot() : x(0), y(0) {}
Robot::Robot(double x, double y) : x(x), y(y) {}
*/
Robot::Robot(double x, double y) {
this->x = x;
this->y = y;
}
//copy constructor
Robot::Robot(const Robot& robot) {
x = robot.x;
y = robot.y;
}
//assignment operator overloading
Robot& Robot::operator=(const Robot& robot) {
x = robot.x;
y = robot.y;
return *this;
}
Robot::~Robot() {}
void Robot::set(double x, double y) {
this->x = x;
this->y = y;
}
double Robot::getX() const {
return x;
}
double Robot::getY() const {
return y;
}
void Robot::move(double dx, double dy) {
x += dx;
y += dy;
}
void Robot::print() const {
using namespace std;
cout << "(x, y) = " << "(" << x << ", " << y << ")" << endl;
}
#include "robot.hpp"
int main() {
//Robot robot0;
//Robot robot0(1);
//Robot robot0(1, 1);
auto robot0 = Robot();
robot0.print();
Robot robot1(robot0);
robot1 = robot0;
robot1.move(1, 1);
robot1.print();
auto robot2 = new Robot;
robot2->move(2, 2);
robot2->print();
delete robot2;
//g++ OK, clang++ OK
const int n = 10;
Robot robot3[n];
for (int i = 0; i < n; i++) {
robot3[i].set(0, 0);
robot3[i].move(3, 3);
robot3[i].print();
}
Robot::nRobots = 10;
auto robot4 = new Robot[Robot::nRobots];
for (int i = 0; i < Robot::nRobots; i++) {
robot4[i].set(0, 0);
robot4[i].move(4, 4);
robot4[i].print();
}
delete[] robot4;
}
set path=d:\sdk\msys64\mingw64\bin;%path%; g++ -std=c++17 -O3 -pedantic-errors -s -Wall -c robot.cpp -o robot.o g++ -std=c++17 -O3 -pedantic-errors -s -Wall -static robot.o main.cpp -o main.exe strip main.exe
オブジェクトをメンバーに持つクラス
#include <iostream>
class X {
public:
double x;
X(double x = 0);
};
X::X(double x) : x(x) {}
class Y {
public:
double y;
Y(double y = 0);
};
Y::Y(double y) : y(y) {}
class Robot {
public:
X x;
Y y;
//引数付きコンストラクタ&デフォルトコンストラクタ
Robot(double x = 1, double y = 1);
};
//引数付きコンストラクタを使ったメンバー初期化リスト
Robot::Robot(double x, double y) : x(x), y(y) {}
/*
Robot::Robot(double x, double y) {
this->x = X(x);
this->y = Y(y);
}
*/
int main() {
X x;
Y y;
std::cout << x.x << std::endl;
std::cout << y.y << std::endl;
//Robot robot; // -> OK
//Robot robot(); // -> NG
//Robot robot(1, 1); // -> OK
//auto robot = Robot(); // -> NG
auto robot = Robot(1, 1);
std::cout << robot.x.x << std::endl;
std::cout << robot.y.y << std::endl;
}
クラスの継承
#include <iostream>
class X {
public:
double x;
X(double x = 0);
};
X::X(double x) : x(x) {}
class Y {
public:
double y;
Y(double y = 0);
};
Y::Y(double y) : y(y) {}
class Robot : public X, public Y {
public:
//引数付きコンストラクタ&デフォルトコンストラクタ
Robot(double x = 1, double y = 1);
};
//スーパークラスの引数付きコンストラクタを使ったメンバー初期化リスト
Robot::Robot(double x, double y) : X(x), Y(y) {}
/*
Robot::Robot(double x, double y) {
X::x = x;
Y::y = y;
}
*/
int main() {
X x;
Y y;
std::cout << x.x << std::endl;
std::cout << y.y << std::endl;
//Robot robot; // -> OK
//Robot robot(); // -> NG
//Robot robot(1, 1); // -> OK
//auto robot = Robot(); // -> NG
auto robot = Robot(1, 1);
std::cout << robot.x << std::endl;
std::cout << robot.y << std::endl;
}
#pragma once
class Array {
public:
static double common;
static const long length = 10;
private:
double element[length];
public:
ArragetY();
double& operator[](long);
};
#include "array.hpp"
#include <cassert>
double Array::common = 0;
Array::ArragetY() {
if (length > 0) {
for (long i = 0; i < length; i++) {
element[i] = 0;
}
}
}
auto Array::operator[](long index) -> double& {
assert(0 <= index && index < length);
return element[index];
}
#include "array.hpp"
#include <iostream>
auto array = ArragetY();
//auto array = new ArragetY(); // -> NG
auto main() -> int {
for (long i = 0; i < Array::length; i++) {
array[i] = i;
std::cout << array[i] << std::endl;
}
std::cout << Array::common << std::endl;
}
#include "array.hpp"
#include <iostream>
auto main() -> int {
auto array = ArragetY();
for (long i = 0; i < Array::length; i++) {
array[i] = i;
std::cout << array[i] << std::endl;
}
std::cout << Array::common << std::endl;
}
#include "array.hpp"
#include <iostream>
auto main() -> int {
auto array = new ArragetY();
for (long i = 0; i < Array::length; i++) {
(*array)[i] = i;
std::cout << (*array)[i] << std::endl;
}
delete array;
std::cout << Array::common << std::endl;
}
set path=d:\sdk\msys64\mingw64\bin;%path%; clang++ -std=c++17 -O3 -pedantic-errors -s -Wall -static *.cpp -o main.exe strip main.exe
注)Windowsのstack領域のサイズは、2MB。
参考サイト
- 記憶領域
- Google:インクルードガード
- オブジェクト指向プログラミングとは結局なんなのか
- C++ クラス設計に関するノート
- 戻り値が参照の関数
- Google:C++ 初期化 代入
- C++における初期化と代入の違い
- C++:value initialization
- C++の初期化
- C++:初期化の種類
- C++:一時オブジェクトの代入
- C++:メンバーイニシャライザー
- C++:クラスのメンバー変数の初期化
- C++:コピーコンストラクターと代入演算子
- C++:デフォルトコピーコンストラクタとデフォルト代入演算子
C++におけるオブジェクト
C++ では、クラス(class)を具象化したものがオブジェクト(object)です。例えて言うなら、クラスは鋳型でオブジェクトは鋳型から作られる鋳物です。C++ のオブジェクトは Java のインスタンス(instance)に相当します。
下記の例では、Robot がクラス、robot、robot0、*robot1、robot00、*robot11 がオブジェクトです。
robot.hpp
#pragma once
class Robot {
double x, y;
public:
static const int robots;
Robot(double x = 0, double y = 0);
~Robot();
auto set(double, double) -> void;
auto getX() const -> double;
auto getY() const -> double;
auto move(double, double) -> void;
auto show() const -> void;
};
robot.cpp
#include <cstdio>
#include "robot.hpp"
const int Robot::robots = 10;
Robot::Robot(double x, double y) : x{x}, y{y} {}
Robot::~Robot() {}
auto Robot::set(double x, double y) -> void {
this->x = x;
this->y = y;
}
auto Robot::getX() const -> double {
return x;
}
auto Robot::getY() const -> double {
return y;
}
auto Robot::move(double dx, double dy) -> void {
x += dx;
y += dy;
}
auto Robot::show() const -> void {
printf("(x, y) = (%5.3f, %5.3f)\n", x, y);
}
main.cpp
#include "robot.hpp"
auto main() -> int {
//Robot robot;
//Robot robot{0, 0};
Robot robot = {0, 0};
robot.move(1, 1);
robot.show();
//auto robot0 = Robot; /* NG */
//auto robot0 = Robot();
//auto robot0 = Robot(0, 0);
auto robot0 = Robot{0, 0};
robot0.move(1, 1);
robot0.show();
//auto robot1 = new Robot;
//auto robot1 = new Robot();
//auto robot1 = new Robot(0, 0);
auto robot1 = new Robot{0, 0};
robot1->move(1, 1);
robot1->show();
delete robot1;
const int length = 10;
Robot robot00[length];
//Robot robot00[Robot::robots]; /* NG */
for (int i = 0; i < length; i++) {
robot00[i] = {0, 0};
robot00[i].move(1, 1);
robot00[i].show();
}
auto robot11 = new Robot[Robot::robots];
for (int i = 0; i < Robot::robots; i++) {
robot11[i] = {0, 0};
robot11[i].move(1, 1);
robot11[i].show();
}
delete[] robot11;
}
〈コンパイル〉
g++ -std=c++17 -O3 -pedantic-errors -s -Wall -static *.cpp -o main.exe strip main.exe
〈コンパイル〉
g++ -std=c++17 -O3 -pedantic-errors -s -Wall -c robot.cpp -o robot.o g++ -std=c++17 -O3 -pedantic-errors -s -Wall -static robot.o main.cpp -o main.exe strip main.exe
参考サイト
C言語によるオブジェクト指向風プログラミング
以下のコードは、構造体のメンバが公開されるオブジェクト指向風プログラミングのコード例です。
#ifndef ROBOT_H
#define ROBOT_H
typedef struct {
double x;
double y;
} Robot;
extern Robot* newRobot(void);
extern void deleteRobot(Robot*);
extern void setRobot(Robot*, double, double);
extern double getxRobot(Robot*);
extern double getyRobot(Robot*);
extern void moveRobot(Robot*, double, double);
extern void printRobot(Robot*);
#endif
#include "robot.h"
#include <stdio.h>
#include <stdlib.h>
Robot* newRobot(void) {
return malloc(sizeof(Robot));
}
void deleteRobot(Robot* robotp) {
free(robotp);
}
void setRobot(Robot* robotp, double x, double y) {
robotp->x = x;
robotp->y = y;
}
double getxRobot(Robot* robotp) {
return robotp->x;
}
double getyRobot(Robot* robotp) {
return robotp->y;
}
void moveRobot(Robot* robotp, double dx, double dy) {
robotp->x += dx;
robotp->y += dy;
}
void printRobot(Robot* robotp) {
printf("x = %f\n", robotp->x);
printf("y = %f\n", robotp->y);
}
#include "robot.h"
int main(void) {
Robot* robotp = newRobot();
setRobot(robotp, 0, 0);
moveRobot(robotp, 1, 1);
printRobot(robotp);
deleteRobot(robotp);
}
以下のコードは、構造体のメンバが隠蔽されるオブジェクト指向風プログラミングのコード例です。
#ifndef ROBOT_H
#define ROBOT_H
typedef struct robot Robot;
extern Robot* newRobot(void);
extern void deleteRobot(Robot*);
extern void setRobot(Robot*, double, double);
extern double getxRobot(Robot*);
extern double getyRobot(Robot*);
extern void moveRobot(Robot*, double, double);
extern void printRobot(Robot*);
#endif
#include "robot.h"
#include <stdio.h>
#include <stdlib.h>
struct robot {
double x;
double y;
};
Robot* newRobot(void) {
return malloc(sizeof(Robot));
}
void deleteRobot(Robot* robotp) {
free(robotp);
}
void setRobot(Robot* robotp, double x, double y) {
robotp->x = x;
robotp->y = y;
}
double getxRobot(Robot* robotp) {
return robotp->x;
}
double getyRobot(Robot* robotp) {
return robotp->y;
}
void moveRobot(Robot* robotp, double dx, double dy) {
robotp->x += dx;
robotp->y += dy;
}
void printRobot(Robot* robotp) {
printf("x = %f\n", robotp->x);
printf("y = %f\n", robotp->y);
}
#include "robot.h"
int main(void) {
Robot* robotp = newRobot();
setRobot(robotp, 0, 0);
moveRobot(robotp, 1, 1);
printRobot(robotp);
deleteRobot(robotp);
}
CとJavaによるオブジェクト指向プログラミング
〈プログラミングの原則〉
一つのプログラムの中に同じようなコードを重複して記述しないこと!
オブジェクト:変数(variable)とその変数を操作する関数(function)の集まり。状態(state)と動作(behaviour)を有する対象。
クラスは鋳型で、インスタンスはクラスから生成される鋳物です。複数のインスタンスをクラスから生成することができます。
オブジェクト指向プログラミングは、以下の場合に用いられます。
- 変数を複数の関数で共有する場合
- 状態遷移や状態に依存する関数を記述する場合
- 2種類の変数に依存する関数を、引数とメンバー変数の関数として表現する場合
注)クラスは、変数や関数を分類するための一種の名前空間です。
注)クラスとインスタンスを総称してオブジェクト(object)と呼ぶことがあります。
注)C++ではメンバー変数(member variable)が、Javaではフィールド(field)が、オブジェクトの状態を表します。
注)手続き型プログラミングは、プログラムの中に頻繁に現れるステートメント(statement)の集まり(手続き)をサブルーチン(subroutine)として再利用するプログラミング技法のことです。
注)オブジェクト指向プログラミングは、関連する変数と手続き(procedure)の集まりをオブジェクト(object)として再利用するプログラミング技法のことです。
以下の例のように、C言語でグローバル変数や参照渡しを使ったプログラムは、オブジェクト指向プログラミングで書き換えることができます。
C言語によるオブジェクト指向風プログラミング(複数のインスタンスを生成できない)
#pragma once
//extern double x, y;
extern void setRobot(double, double);
extern void moveRobot(double, double);
extern void printRobot(void);
#include <stdio.h>
static double x, y;
void setRobot(double x0, double y0) {
x = x0;
y = y0;
}
void moveRobot(double dx, double dy) {
x += dx;
y += dy;
}
void printRobot(void) {
printf("x = %f\n", x);
printf("y = %f\n", y);
}
#include "robot.h"
int main(void) {
setRobot(0, 0);
moveRobot(1, 1);
printRobot();
}
C言語によるオブジェクト指向風プログラミング(複数のインスタンスを生成できる)
#pragma once
typedef struct {
double x, y;
} Robot;
extern void setRobot(Robot*, double, double);
extern void moveRobot(Robot*, double, double);
extern void printRobot(Robot*);
#include "robot.h"
#include <stdio.h>
void setRobot(Robot* robotp, double x, double y) {
robotp->x = x;
robotp->y = y;
}
void moveRobot(Robot* robotp, double dx, double dy) {
robotp->x += dx;
robotp->y += dy;
}
void printRobot(Robot* robotp) {
printf("x = %f\n", robotp->x);
printf("y = %f\n", robotp->y);
}
#include "robot.h"
int main(void) {
Robot robot1;
setRobot(&robot1, 0, 0);
moveRobot(&robot1, 1, 1);
printRobot(&robot1);
Robot robot2;
setRobot(&robot2, 0, 0);
moveRobot(&robot2, 2, 2);
printRobot(&robot2);
}
Javaによるオブジェクト指向プログラミング
class Robot {
double x, y;
void set(double x, double y) {
this.x = x;
this.y = y;
}
void move(double dx, double dy) {
x += dx;
y += dy;
}
void print() {
System.out.println("x = " + x);
System.out.println("y = " + y);
}
}
class Main {
public static void main(String... args) {
Robot robot1 = new Robot();
robot1.set(0, 0);
robot1.move(1, 1);
robot1.print();
Robot robot2 = new Robot();
robot2.set(0, 0);
robot2.move(2, 2);
robot2.print();
}
}
参考サイト
アセンブリのお勉強
検索と置換!
転送命令、分岐命令、比較命令があれば、どんな演算でも新たに作ることができます!
以下では、Intel syntax に従います。また、CPU は 16bit とします。
0.Instruction
Instruction = Opcode (Operation Code) + Operands
Operand:immediate value, register, memory, I/O port
1.Move Instruction (Transfer Instruction)
1-1.Unconditional Move Instruction
mov destination, source ;transfer source to destination
1-2.Conditional Move Instruction
cmoveとcmovz、cmovneとcmovnzのマシーンコードは同じです。
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)スタックポインタが指す位置にオペランド(source)のサイズだけデータが積み込まれる。
〈POP命令の流れ〉
0)POP命令の実行前にインストラクションポインタが命令長分だけインクリメントする。(POP命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)POP命令が実行されると、スタックポインタが指す位置からオペランド(destination)のサイズだけデータが取り出される。
2)スタックポインタがスタックから取り出したデータのサイズ(operand-size attribute)だけインクリメントする。
push source ;transfer source to [sp]
pop destination ;transfer [sp] to destination
1-4.I/O Instruction
I/O命令は、CPUのレジスタとI/Oポート間の転送命令です。destination 及び source にはレジスタを指定し、port-address は、即値またはレジスタで指定します。 尚、[port-address] は、port-address で指定されたI/Oポートを表します。
in destination, port-address ;transfer [port-address] to destination
out port-address, source ;transfer source to [port-address]
2.Jump Instruction (Branch Instruction)
ジャンプ命令は、インストラクションポインタ(ip)への転送命令です。
2-1.Unconditional Jump Instruction
jmp source ;set ip to source
2-2.Conditional Jump Instruction
jeとjz、jneとjnzのマシーンコードは同じです。
je source ;zf == 1 → set ip to source
jne source ;zf == 0 → set ip to source
jcxz は、cx が 0 でなければ何もせず、cx が 0 になればオペランドにジャンプします。
start:
mov cx 10
loop:
・・・・・・・
dec cx
jcxz break ;cx == 0 → jump to break
jmp loop:
break:
・・・・・・・
2-3.Unconditional Loop Instruction with Count Register
loop は、cx をディクリメントした後、cx が 0 でなければオペランドにジャンプし、cx が 0 になればループを抜けます。
loop source ;cx--, cx != 0 → set ip to source
start:
mov cx 10
label:
・・・・・・・
loop label
・・・・・・・
2-4.Conditional Loop Instruction with Count Register
loopeとloopz、loopneとloopnzのマシーンコードは同じです。
loope source ;cx--, cx != 0 and zf == 1 → set ip to source
loopne source ;cx--, cx != 0 and zf == 0 → set ip to source
2-5.CALL Instruction and RET Instruction
CALL命令及びRET命令は、ジャンプ命令の一つです。
〈CALL命令の流れ〉
0)CALL命令の実行前にインストラクションポインタが命令長分だけインクリメントする。(CALL命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)CALL命令が実行されると、インストラクションポインタの値がスタックに転送される。(インストラクションポインタがプッシュされる)
2)呼び出し先のアドレス(CALL命令のオペランド)がインストラクションポインタにセットされる。
〈RET命令の流れ〉
0)RET命令の実行前にインストラクションポインタが命令長分だけインクリメントする。(RET命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)RET命令が実行されると、スタックの値がインストラクションポインタに転送される。(インストラクションポインタにポップされる)
サブルーチンでレジスタを使用するときは、次の例ようにPUSH命令で使用するレジスタの値を一旦スタックに退避(save)させておき、レジスタを使い終わったらPOP命令で元の値に復元(restore)します。 また、PUSHA命令、POPA命令は、それぞれ全てのレジスタをPUSH、POSする命令です。
start:
call sub1
call sub2
sub1:
push ax
push bx
push cx
mov ax, 0
mov bx, 0
mov cx, 0
pop cx
pop bx
pop ax
ret
sub2:
pusha
・・・・・・・
popa
ret
次の例では、スタックを使ってサブルーチンに値を渡しています。(レジスタやメモリを使ってサブルーチンに値を渡すこともできます)
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
short addxyz(short x, short y, short z) {
return x + y + z;
}
int main(void) {
addxyz(1, 2, 3);
}
2-6.Software Interrupt Instruction
ソフトウェア割り込み命令は、ジャンプ命令の一つです。INT命令及びIRET命令は、それぞれCALL命令及びRET命令に対応しています。
int (interrupt number)
int 0x21 ;DOS System Call
int 0x80 ;Linux System Call
iret
3.Compare Instruction
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 |
X XNOR Y ≡ (X∧Y)∨(¬X∧¬Y)
4.Other Instructions
4-1.Increment Instruction and Decrement Instruction
inc state ;state + 1 -> state
dec state ;state - 1 -> state
4-2.Arithmetic Instruction
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
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)
shl state, count
shr state, count
rol state, count
ror state, count
4-5.No Operation Instruction and Halt Instruction
nop
hlt
Appendix
A-1.Addressing Mode
Address Space:memory address space, I/O address space
Addressing Mode:immediate addressing, absolute addressing, ralative addressing, direct addressing, indirect addressing
A-2.I/O Controller (Device Controller)
Processor ⇔ I/O Controller (Device Controller) ⇔ I/O Device (Peripheral Device)
I/O Controller:status register、command register (control register)、input register、output register
参考サイト
- x86 Assembly
- Assembly Programming
- x86 Instruction Set Reference
- NASM (Netwide Assembler)
- Central Processing Unit instructions set
- アセンブリ言語の基礎知識
- アセンブリ言語の基礎知識 Part5
- x86アセンブリ言語での関数コール
- ARM Instruction Sets
- Conditional Move Instructions
- CMP命令とフラグの変化
- 比較命令とジャンプ命令
- Jump and Branch Instructions
- LOOP/LOOPcc
- Bit Shift and Rotate Instructions
- 新・コンピュータ解体新書
- 独習アセンブラ
- Processor-I/O Controller Interactions
七夕
今日は七夕です!