SlideShare a Scribd company logo
ソフトウェア工学
nコードフォーマット
• コード規約,PEP8,チェッカー,フォーマッタ,難読化
玉木徹(名工大)
コード規約
コーディング規約
nコードスタイルを統一する
• コードの書き方を統一し可読性を高めることが目的
• 様々な流派がある
• 通常はプロジェクト毎に指定される
• 言語毎に標準がある場合もある
n可読性が重要な理由
• 「コードは書くよりも読まれることの方が多い」
PEP8ドキュメント https://pep8-ja.readthedocs.io/ja/latest/#id4
コーディング規約の例
nインデントの個数
int main(void){
int i;
for(i = 0; i < 10; i++){
printf(“hello world”);
}
return 0;
}
int main(void){
int i;
for(i = 0; i < 10; i++){
printf(“hello world”);
}
return 0;
}
インデント2文字分
• 1行が短い
インデント4文字分
• ブロックがわかりやすい
注:タブ(1文字)でもエディタ上ではお
なじに見えてしまう
• 半角スペースを4文字分使う(通常)
• タブを1文字分使う(普通はやらな
い)
こちらが標準的
コーディング規約の例
n{}をつける位置
int main(void){
int i;
for(i = 0; i < 10; i++){
printf(“hello world”);
}
return 0;
}
int main(void)
{
int i;
for(i = 0; i < 10; i++)
{
printf(“hello world”);
}
return 0;
}
「{」は行末
• コード行数が少ない
「{」は行頭
• スコープがわかりやすい
コーディング規約の例
n()や演算子の前後の空白の有無
int main(void){
int i;
for(i = 0; i < 10; i++){
printf(“hello world”);
}
return 0;
}
int main (void) {
int i;
for (i=0; i<10; i++) {
printf (“hello world”);
}
return 0;
}
空白を空けない
• 1行が短い
空白を空ける
• わかりやすい
こちらが標準的
コーディング規約の例
n空白行の数
int main(void){
int i;
for(i = 0; i < 10; i++){
printf(“hello world”);
}
return 0;
}
int main(void){
int i;
for(i = 0; i < 10; i++){
printf(“hello world”);
}
return 0;
}
空行を入れない
• コード行数が少ない
空行を入れる
• まとまりがわかり
やすい
命名規則:変数名の付け方の約束
nケース:大文字(upper case)や小文字(lower case)のこと
n大文字小文字でつなげるキャメルケース(Camel:らくだ)
• camelCase (lowerCamelCase)
• CamelCase (UpperCamelCase, PascalCase, CapWords)
nアンダースコアでつなげるスネークケース(snale:ヘビ)
• snake_case
• UPPER_SNAKE_CASE
nハイフンでつなげる(kebab:ケバブは串刺し料理)
• kebab-case (chain-case)
n型を冒頭に付ける
• ハンガリアン記法:pCamelCase
名前の付け方:変数,関数,クラス
n英語を使う
• 日本語(ローマ字)は使わない
• tasu() à add()
• hensuとかkansuはダメ!
n対象を具体的に,機能を明確に
する
• add() à add_two_num()
n一般的なやり方で省略する
• get_number_of_users() à
getNumUsers(),
get_num_users()
• compute_distance_probabili
nよくある付け方も知っておく
• is:状態を表すフラグ
• isCreated, is_created
(それが作られたかどうかの真
偽値)
• has:持っているかどうか
• hasPred, has_pred
(Predictionメソッドを持っ
ているか)
n現役SEのネット情報も参考に
• うまくメソッド名を付けるための参考情報
• 変数の命名―わかりやすい名前の付け方はこれ
だ!
• 変数名・関数名の付け方についての個人的ルー
ル
統一的なコーディング規約
nプロジェクト毎の規約では
• 他のプロジェクトではコード規約
を覚え直すことになる
n言語で統一したものがある
• 誰もがそれに従えば標準的なコー
ドを書ける
• Python:PEP8(Python
Enhancement Proposal)
• PHP: PSR-0/1/2(PHP Standards
Recommendations)
n標準的な規約を使うことが多い
• 一般的に多くのプロジェクトでよ
く使われているもの
• Google Style Guides
• 各種言語用あり(C#, C++, Java,
Python, etc)
• Javaには色々ある
nスタイルだけでなくセキュアな
コーディング規約も
• CERTセキュアコーディング標準
• C/C++, Java
• MISRA-C(高信頼性車載組み込み
向け)
良いコードを書くことは技術=練習が必要
Good Code, Bad Code 〜持続
可能な開発のためのソフトウェ
アエンジニア的思考
TomLong, 秋勇紀
他 | 2023/1/28
リーダブルコード ―より良い
コードを書くためのシンプルで
実践的なテクニック (Theory in
practice)
Dustin Boswell , Trevor
Foucher他 | 2012/6/23
良いコード/悪いコードで学ぶ
設計入門―保守しやすい 成長
し続けるコードの書き方
仙塲 大也 | 2022/4/26
[増補改訂]良いコードを書く技術
── 読みやすく保守しやすいプ
ログラミング作法 (WEB+DB
PRESS plus)
縣 俊貴 | 2021/4/28
PEP8解説
https://pep8-ja.readthedocs.io/ja/latest/ より
Public Domain
© Copyright 2014, Yoshinari Takaoka
インデント
n # 正しい:
# 開き括弧に揃える
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 引数とそれ以外を区別するため、スペースを4つ(インデントをさらに)加える
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
# 突き出しインデントはインデントのレベルを深くする
foo = long_function_name(
var_one, var_two,
var_three, var_four)
1レベルインデントするごとに、スペースを4つ使いましょう。
インデント
n # 間違い:
# 折り返された要素を縦に揃えない場合、1行目の引数は禁止
foo = long_function_name(var_one, var_two,
var_three, var_four)
# インデントが区別できないので、2行目以降でさらにインデントが必要
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
1レベルインデントするごとに、スペースを4つ使いましょう。
演算子の前で改行すべきか、後で改行すべきか?
n # 間違い:
# 演算子がオペランドと離れてしまっている
income = (gross_wages +
taxable_interest +
(dividends - qualified_dividends) -
ira_deduction -
student_loan_interest)
演算子の前で改行すべきか、後で改行すべきか?
n # 正しい:
# 演算子とオペランドを一致させやすい
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
1行は80文字以下
n1行の長さ
• すべての行の長さを、最大79文字までに制限しましょう。
• ほとんどのツールのデフォルトの折り返し動作は、コードの見た目の構造を壊
し、理解するのを難しくします。79文字という制限は、ウィンドウの幅を80
に制限し、行を折り返すときにツールが行末にマーカーを置いたとしても、エ
ディタに折り返す動作をさせない目的で選ばれています。
エディタの設定に
よっては80文字のと
ころに線が出る
式や文中の空白文字
n括弧やブラケット、波括弧 のはじめの直後と、終わりの直前:
• # 正しい: spam(ham[1], {eggs: 2})
• # 間違い: spam( ham[ 1 ], { eggs: 2 } )
n末尾のカンマと、その後に続く閉じカッコの間:
• # 正しい: foo = (0,)
• # 間違い: bar = (0, )
nカンマやセミコロン、コロンの直前:
• # 正しい: if x == 4: print x, y; x, y = y, x
• # 間違い: if x == 4 : print x , y ; x , y = y , x
余計な空白文字を使うのはやめましょう
式や文中の空白文字
n# 正しい:
• ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
• ham[lower:upper], ham[lower:upper:], ham[lower::step]
• ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
• ham[lower + offset : upper + offset]
n# 間違い:
• ham[lower + offset:upper + offset]
• ham[1: 9], ham[1 :9], ham[1:9 :3]
• ham[lower : : upper]
• ham[ : upper]
余計な空白文字を使うのはやめましょう
式や文中の空白文字
n関数呼び出しの引数リストをはじめる開き括弧の直前:
• # 正しい: spam(1)
• # 間違い: spam (1)
nインデックスやスライスの開き括弧の直前:
• # 正しい: dct['key'] = lst[index]
• # 間違い: dct ['key'] = lst [index]
n代入(や他の)演算子を揃えるために、演算子の周囲に1つ以上のス
ペースを入れる:
• # 正しい:
x = 1
y = 2
long_variable = 3
余計な空白文字を使うのはやめましょう
• # 間違い:
x = 1
y = 2
long_variable = 3
式や文中の空白文字
n 関数呼び出しの引数リストをはじめる開き括弧の直前:
• # 正しい: spam(1)
• # 間違い: spam (1)
n インデックスやスライスの開き括弧の直前:
• # 正しい: dct['key'] = lst[index]
• # 間違い: dct ['key'] = lst [index]
n 代入(や他の)演算子を揃えるために、演算子の周囲に1つ以上のスペースを
入れる:
• # 正しい:
x = 1
y = 2
long_variable = 3
余計な空白文字を使うのはやめましょう
• # 間違い:
x = 1
y = 2
long_variable = 3
• これは間違い!!!
x=1
y=2
if a>0 and b<0:
z = 2*y + 4/b
• 正しくは
x = 1
y = 2
if a > 0 and b < 0:
z = 2 * y + 4 / b
演算子前後の空白は「余計
な空白」ではない!
守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のアイ) を決して
変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があり
ます。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いましょう。
nフォントにはこだわれ
フォント:Arial/Helvetica
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Arial/Helveticaは使わない!
• プロポーショナルフォントだから揃わない
• lとI,0とOが紛らわしい
守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のアイ) を決して
変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があり
ます。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いましょう。
nフォントにはこだわれ
フォント:Times / Times New Roman
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Timesは使わない!
• プロポーショナルフォントだから揃わない
• そもそもセリフ系のフォントでコーディングしない
守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のア
イ) を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があ
ります。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いま
しょう。
nフォントにはこだわれ
フォント:Courier
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Courierはまだまし
• 等幅フォントだから揃ってOK
• まだ0とOが紛らわしい
守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のアイ)
を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があり
ます。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いましょ
う。
nフォントにはこだわれ
フォント:Consolas (win)
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Consolasならよし
• 等幅フォントだから揃ってOK
• 0とOの区別がつく
守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のア
イ) を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があ
ります。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いま
しょう。
nフォントにはこだわれ
フォント:Menlo (mac)
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Menloならよし
• 等幅フォントだから揃ってOK
• 0とOの区別がつく
守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のア
イ) を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があ
ります。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いま
しょう。
nフォントにはこだわれ
フォント:Source Code Pro
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Source Code Proならよし
• 等幅フォントだから揃ってOK
• 0とOの区別がつく
守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のア
イ) を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があ
ります。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いま
しょう。
nフォントにはこだわれ
フォント:Source Code Pro
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Source Code Proならよし
• 等幅フォントだから揃ってOK
• 0とOの区別がつく
自分でフォントをインストールしよう
• プログラミングが捗りすぎる!コーディングに
最適なフォント12選
• 少しでもコーディングするなら“コーディング用
フォント”を導入しよう
• Top Programming Fonts
守るべき命名規約
nパッケージとモジュールの名前
• モジュールの名前は、全て小文字の短い名前にすべきです。読みやすくなるな
ら、アンダースコアをモジュール名に使っても構いません。Python のパッ
ケージ名は、全て小文字の短い名前を使うべきですが、アンダースコアを使う
のは推奨されません。
nクラスの名前
• クラスの名前には通常 CapWords 方式を使うべきです。
n型変数の名前
• PEP484で導入された型変数の名前には、通常CapWords方式を使うべきです。
また、TやAnyStrやNumのような短い名前が好ましいです。
CamelCase
CamelCase
snakecase
守るべき命名規約
n関数や変数の名前
• 関数の名前は小文字のみにすべきです。また、読みやすくするために、必要に
応じて単語をアンダースコアで区切るべきです。
• 変数の名前についても、関数と同じ規約に従います。
nメソッド名とインスタンス変数
• 関数の命名規約を使ってください。つまり、名前は小文字のみにして、読みや
すくするために必要に応じて単語をアンダースコアで区切ります。
n定数
• 全ての定数は大文字で書き、単語をアンダースコアで区切ります。例とし
て MAX_OVERFLOW や TOTAL があります。
snake_case
snake_case
SNAKE_CASE
import unittest
# from compute import myadd, mymult
from unittest.mock import MagicMock
myadd = MagicMock()
mymult = MagicMock()
from integration import AddOrMult
def is_mock(obj):
return obj.__class__.__name__ == 'MagicMock'
class TestAddOrMult(unittest.TestCase):
def test_add(self):
if is_mock(myadd):
myadd.return_value = 8
add_or_mult = AddOrMult(myadd, mymult)
val = add_or_mult.do(2, 6, 'add')
self.assertEqual(8, val)
def test_mult(self):
if is_mock(mymult):
mymult.return_value = 12
add_or_mult = AddOrMult(myadd, mymult)
val = add_or_mult.do(2, 6, 'mult')
self.assertEqual(12, val)
if __name__ == "__main__":
unittest.main()
実際の例:テストコード
パッケージ名
snakecase
クラス名
CamelCase
関数名
snake_case
クラス名
CamelCase
メソッド名
snake_case
メソッド名
camelCase
(PEP8にしたがっていない!)
test_integration.py
code
checker & formatter
docker composeの準備
起動する
$ cd 11_01_formatting
$ docker compose build
$ docker compose up -d
確認する
$ docker compose ps
停止する
$ docker compose down
チェッカーとフォーマッタ
nチェッカー
• 規約に沿っているかどうかをチェック
• Python用PEP8チェッカー
• flake8, pylint, pycodestyle
nフォーマッター
• 規約に沿ったコードに修正
• 別名:beautifier, prettier
• 修正をformattingやbeautificationとも言う
• Python用PEP8フォーマッター
• autopep8, black, yapf
規約を守っていない
イマイチなコード
def myfunc(x, y):
z= 2*x - y
return z
def myfunc_2(a):
for i in range(5):
myfunc( a[i],a[i + 1] )
def myfunc_3(a):
for i in range(5):
myfunc(a[ i ], a[i+ 1])
def main():
a=[1,2,3,4,5]
for _ in range(100):
myfunc_2(a)
for _ in range(300):
myfunc_3 (a)
if __name__ == '__main__':
main()
$ docker compose exec mypython flake8 main.py
main.py:4:6: E225 missing whitespace around operator
main.py:4:9: E226 missing whitespace around arithmetic operator
main.py:9:1: E303 too many blank lines (3)
main.py:11:16: E201 whitespace after '('
main.py:11:21: E231 missing whitespace after ','
main.py:11:30: E202 whitespace before ')'
main.py:13:1: E302 expected 2 blank lines, found 1
main.py:15:18: E201 whitespace after '['
main.py:15:20: E202 whitespace before ']'
main.py:15:27: E225 missing whitespace around operator
main.py:19:6: E225 missing whitespace around operator
main.py:19:9: E231 missing whitespace after ','
main.py:19:11: E231 missing whitespace after ','
main.py:19:13: E231 missing whitespace after ','
main.py:19:15: E231 missing whitespace after ','
main.py:21:8: E111 indentation is not a multiple of 4
main.py:23:8: E111 indentation is not a multiple of 4
main.py:23:16: E211 whitespace before '('
$
Flake8によるコードチェック
チェックするファイ
ル名(指定しなけれ
ばpwdのファイルをす
べて)
$ docker compose exec mypython flake8 --show-source main.py
main.py:4:6: E225 missing whitespace around operator
z= 2*x - y
^
main.py:4:9: E226 missing whitespace around arithmetic operator
z= 2*x - y
^
main.py:9:1: E303 too many blank lines (3)
def myfunc_2(a):
^
main.py:11:16: E201 whitespace after '('
myfunc( a[i],a[i + 1] )
^
main.py:11:21: E231 missing whitespace after ','
myfunc( a[i],a[i + 1] )
^
main.py:11:30: E202 whitespace before ')'
myfunc( a[i],a[i + 1] )
^
main.py:13:1: E302 expected 2 blank lines, found 1
Flake8によるコードチェック
対応するソー
ス行を表示
autopep8によるフォーマッティング
修正前のコード 修正後のコード
def myfunc(x, y):
z = 2 * x - y
return z
def myfunc_2(a):
for i in range(5):
myfunc(a[i], a[i + 1])
def myfunc_3(a):
for i in range(5):
myfunc(a[i], a[i + 1])
def main():
a = [1, 2, 3, 4, 5]
for _ in range(100):
myfunc_2(a)
for _ in range(300):
myfunc_3(a)
if __name__ == '__main__':
main()
def myfunc(x, y):
z= 2*x - y
return z
def myfunc_2(a):
for i in range(5):
myfunc( a[i],a[i + 1] )
def myfunc_3(a):
for i in range(5):
myfunc(a[ i ], a[i+ 1])
def main():
a=[1,2,3,4,5]
for _ in range(100):
myfunc_2(a)
for _ in range(300):
myfunc_3 (a)
if __name__ == '__main__':
main()
autopep8によるフォーマッティング
修正するソースファイルを直接書き換
える(上書き,--in-place)
-aなし
-aあり
-aをつけると演算子前後の空白まで厳
密に修正(aggressive)
def myfunc(x, y):
z= 2*x - y
return z
def myfunc(x, y):
z= 2*x - y
return z
def myfunc(x, y):
z= 2 * x - y
return z
$ docker compose exec mypython autopep8 -i main.py
$ docker compose exec mypython autopep8 -a -i main.py
VScodeでflake8
もしくはpylint
拡張機能を入れ
よう
pythonで検索
Microsoftの
python拡張をインス
トール
コマンドパレットから
select linter
を検索して...
flake8を選択
(pylintでもOK)
(pycodestyleでもOK)
コード中にflake8結果が
波線で表示される
マウスオーバーで内容が
表示される
settings.jsonでの設定
settings.json
の中に設定がある
必要なものを
設定する
setup.cfgでの設定
setup.cfg
の中に設定がある
それぞれ
必要なものを
設定する
VScodeでautopep8
もしくはblack, yapf
settings.jsonでの設定
settings.json
の中に設定がある
つかうフォーマッタを
残す
autopep8のオプション
yapfのオプション
blackのオプション
pyproject.tomlでの設定
setup.cfg
の中に設定がある
それぞれ
必要なものを
設定する
フォーマットするタイミングの設定
editor.formatOnSaveをtrueにすると
ファイルを保存するたびにフォーマッタが実行される
onFocusChangeにすると,
フォーカスが変わった瞬間に
ファイルが保存されて
フォーマッタが実行される
保存前
まだフォーマットされて
いない
保存した瞬間にフォー
マットが実行される
autopep8での演算子前後の空白設定
Autopep8 Argsに
-a -a
を追加するともっと厳密に修正する
-aなし
-aあり
1行80文字までの設定
80にすると
80文字の線が
表示される
C++/Javaの
フォーマッティング
詳しい設定はsettings.jsonを参照
C/C++のフォーマッティング
Javaのフォーマッティング
各種オンラインツール
python online formatter
などで検索すると多数見つかる
オンラインツール
https://www.tutorialspoint.com/online_python_formatter.htm
オンラインツール https://black.now.sh
難読化
ビルドとは
n コードをコンパイルして実行形式ファイルなどを作成すること
• C, C++など
コンパイラ リンカ
ソース
ファイル
オブジェクト
ファイル
静的ライブラリ
(*.a)
実行
ファイル
静的
リンク
コンパイル
実行
ファイル
共有ライブラリ (*.so)
DLL
動的
リンク
ビルド 実行
リバースエンジニアリング
n実行形式(バイナリ)ファイルからソースコードに戻すこと
コンパイラ リンカ
ソース
ファイル
オブジェクト
ファイル
静的ライブラリ
(*.a)
実行
ファイル
静的
リンク
コンパイル
ビルド
リバースエンジニアリング
• 失われたソースコー
ドを復旧したい
• 技術を盗みたい
• コピーして無料で使
いたい
大抵のライセンスでは
ユーザーのリバースエ
ンジニアリングを禁止
している
ユーザー
n納品先(発注側)のユーザーが
リバースエンジニアリング
• 再度発注しなくてよい...
• (注:違法です!)
発注側 受注側
保守の金額高
いですね
了解
リバースエン
ジニアリング
して修正は自
分達でやれば
無料!
納品後も保守修正
する契約をとって
こい
ビルドできたので
リリースできます
実行ファイル
で納品します
保守修正も承
りますが
実行ファイル
受け取りまし
た
保守修正の依
頼は検討しま
す
元請け
n元請けがリバースエンジニアリング
• 安い元請けに流す...
• (注:違法です!)
• 技術の流出
発注者 元請け
納品します
受け取りまし
た
最初の下請け
できました
納品します
受け取りまし
た
元請け
n元請けがリバースエンジニアリング
• 安い元請けに流す...
• (注:違法です!)
• 技術の流出
発注者 元請け 最初の下請け
安い下請け
ありがとうご
ざいます!
このシステム
をまた発注し
ます
そうです
か...
残念ですが今
回は...
了解です
前回のベンダのバイ
ナリをリバースエン
ジニアリングして
使って安くして
難読化
nC, C++などコンパイルする言語
• 実行バイナリを納品
• リバースエンジニアリングは困難
nPythonなどスクリプト言語
• スクリプト=ソースコードを納品
• リバースエンジニアリングどころ
かコードがそのまま納品物!
n難読化(obfuscation)
• ソースコードを人間が内容を理解
できないように改変する
• 技術流出のリスクを下げる
• ただし実行結果は同一
• 納品物としての品質は保つ
n方法(Python用)
• コードの改変
• pyminifier, pyobfuscateなど
• 限界あり
• コンパイル
• Cython
• 元々は高速に実行するため
• バイナリ変換
• PyArmor
• 配布用
• ライセンス期限などをつけ
られる
docker composeの準備
起動する
$ cd 11_02_obfuscation
$ docker compose build
$ docker compose up -d
確認する
$ docker compose ps
停止する
$ docker compose down
def myfunc(x, y):
z = 2*x - y
return z
def myfunc_2(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def myfunc_3(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def main():
a = [1, 2, 3, 4, 5, 6]
result = []
for _ in range(100):
result.extend(myfunc_2(a))
def n(x,y):
B=range
E=print
o=sum
z=2*x-y
return z
def P(a):
C=[]
for i in B(5):
C.append(n(a[i],a[i+1]))
return C
def H(a):
C=[]
for i in B(5):
C.append(n(a[i],a[i+1]))
return C
def T():
a=[1,2,3,4,5,6]
C=[]
for _ in B(100):
C.extend(P(a))
pyminifierの結果
docker compose exec mypython pyminifier --obfuscate-builtins --obfuscate main.py > main.obs.py
まだ読める
pyobfuscateの結果
読めない...?
docker compose exec mypython pyobfuscate -i main.py > main.obs.py
def myfunc(x, y):
z = 2*x - y
return z
def myfunc_2(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def myfunc_3(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def main():
a = [1, 2, 3, 4, 5, 6]
result = []
for _ in range(100):
result.extend(myfunc_2(a))
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
oooooooooo =
"xUrwqqTNfOoJyaMUpmtJnidmcaIEoJLkMmzlVLyeABdgivVIvnwXXWOlYuJWxIsUurKRNUeGGGEcbzl"
IlIIIlIllIIIIllIIlIlIIlIlIIIIIIlllllIIlIllIIlIlllIIIlllIllIIIIlIIIIIlIIlIIllIIIllIIllIII
lllIIllI = 871
AAaaAAAAAAaaaAaaAAaAaaaaAaaaaAAaAAaaaaaAaaaAAaAaAAAAaAAaaAAAaaaaAaAaAAAaaaAaAAaaaaAaAAAA
aAaAaA = 467
l92 = "EJzsVneoODfWOzyIyoAxftCdOpiPPfhaDpgfrhskQWPzKJZcTRdVLAXcYmOQIubPmqnfRFVFwBnRycJ"
aAAAaaaAaaAaAaaaAAaAaaaaAAaAAaAaaaAAAaAAAaAaAaaAAaaaAaAAAaAaAaaAAAaAAaAAAaaaaaAaaaAAaaAa
Aa = "gDypupGxpWeekIQHmuWGBWWDwZaQebOEqzdLVIgdbYUCMXcFViegYYcghZMUQRzeShFfjKEDgROWesn"
d1683520267749028788 =
"PpUxLRzwcmlsYLXdHPAfeBMZlSyRXZCjeHHmzpMCjYrrXXNoWUkztBpqZlZyJRtfTAKKEknLYenmUOg"
X86 = 487
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt =
"KpvKamIbTiuUCkRarRHuPrPSyxFGsoSTmVbTCmEmHuLiemmyyWMCBhLjsKabJeeRBsTzsXQFMQYhdAf"
k82 = "MXKTtzWXLzaFrCGPXFWQbtkbDnJQIArMDbizyTIHKUkfBjXMkwUuBVykfoumSJFEmsVPQZZoqLmQZlt"
gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg =
"bCNmYIZMgRdpYAamdhhzmkNpdUobnMvNRXzLYKfZwmaFxOgyRjtylSxnGtcYVlddyzcvBWPoxswhpwR"
lIIIlIIllllllIlllIIlIlIlIllIIllllllllllIIIIIllIIIlIlIlIIlIIllIlIlIIlIIlIlIlIll = 525
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB = 130
AAAaaaAAaaAAAAAaAaaaAaaAAAAAAaAaaaAaAAaaaAaaAaAaAaaaAAaaaAaAAAaaaAAAaAaAaa =
"LvytqzgdnykIOztMqkAXAMtkZgyukklBhrfzYlkHKcWHIbBvcvVUgZKxwrcFokoUEvkRqcYkYoohHmD"
AaAAAaaaaAaAaAaaAaAaaAaaaAaAaaaaAaaAAaAAAaAAaAaAaAaaAAaAaaAAaaaaAAAaAaaA = 252
voUQpSVTHMbtlAISqZwetKnkUePETXwGKSKdvJtrJxbIhiMmbqTqGxchnWGBOewivYHNEYNSYpehppd70 = 99
IlIIIllIlIlllIllllIllIlIIlIIllllIIIlllIlIlIIlllIlIIlIIIIIIlllIIlIlII = 414
IIIllIllIllIlIlIllIllIlIIlIIIlIIlIIIlIlIIIlIIllIlIllIlIlllIlIIllIl =
"QeDpOELsHZgwdeJWbCeHuwODdybAydXpQlwUvmjvHTNyZZIBqGbiixSrQkdMTZnnMPgaIgoIUQvWWML"
U168352026774849364 = 192
S62 = "zqNYnZzbElmhDfthMMykorqeBjgeNKPndANhDYyuujvaCgFyvPUzTBFSsxjLbCckbAGoSFLvhsyqZjc"
AAaaAAaAaaAaaaaAaAaaaaaAaAAaaaaAAAAAAaAAAAaAaaaAaaaaaaaAaaAA = 281
F58 = 622
v168352026774831856 =
"VEbAlmlWXjnCjuQWuJNYxWntwrAcITqnJLQjsBWCdDlATDpgTUZuCQSOjpbQYinuvXkFgFkebaHHAMH"
...
pyobfuscateの結果
途中から読める
docker compose exec mypython pyobfuscate -i main.py > main.obs.py
def myfunc(x, y):
z = 2*x - y
return z
def myfunc_2(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def myfunc_3(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def main():
a = [1, 2, 3, 4, 5, 6]
result = []
for _ in range(100):
result.extend(myfunc_2(a))
IIlIIlIllIIl =
"UgUzfycOkxWVxMWDYPvadsgGBdQKJAQfDYMFFZmgFUcIoGKiLqQIbTSjOOeRlusHDufwZUTkYGWCenC"
llIIllllII = 112
aAAaAaaA = 612
CCCCCC = 634
lIIl = "wnaMMWLpZvypOpawfxkhcfVxvrUewstjYreHuEsxvdaQsYFFFUjFTfdlHyBkGfQxMPfdkiBqLiOiXjZ"
Il = 365
def myfunc(x, y):
MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyxivOTwfaWy4 =
2*x - y
return
MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyxivOTwfaWy4
def
myfunc_2(MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyxivOTwfaWy
4):
aA = []
for i in range(5):
aA.append(myfunc(MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKpr
zfyNoyxivOTwfaWy4[i],
MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyx¥
ivOTwfaWy4[i + 1]))
return aA
def
myfunc_3(MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyxivOTwfaWy
4):
aA = []
for i in range(5):
aA.append(myfunc(MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKpr
zfyNoyxivOTwfaWy4[i],
MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyx¥
ivOTwfaWy4[i + 1]))
return aA
Online Obfuscator
https://pyob.oxyry.com
読めるが変数名が
ほぼ区別不可能
$ docker compose exec mypython pyarmor gen main.py
INFO Python 3.11.3
INFO Pyarmor 8.1.9 (trial), 000000, non-profits
INFO Platform linux.x86_64
INFO search inputs ...
INFO find script main.py
INFO find 1 top resources
INFO start to generate runtime files
INFO target platforms {'linux.x86_64'}
INFO write dist/pyarmor_runtime_000000/pyarmor_runtime.so
INFO patch runtime file
INFO generate runtime files OK
INFO start to obfuscate scripts
INFO process resource "main"
INFO obfuscating file main.py
INFO write dist/main.py
INFO obfuscate scripts OK
$
PyArmorによる難読化
難読化するファイル名
難読化の指定
生成される
配布用 (dist)
の難読化
コードと実
行用ライブ
ラリ
PyArmorによる難読化
main.py dist/main.py
def myfunc(x, y):
z = 2*x - y
return z
def myfunc_2(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def myfunc_3(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def main():
a = [1, 2, 3, 4, 5, 6]
result = []
for _ in range(100):
result.extend(myfunc_2(a))
for _ in range(300):
result.extend(myfunc_3(a))
print(sum(result))
if __name__ == '__main__':
main()
# Pyarmor 8.1.9 (trial), 000000, non-profits, 2023-05-
07T13:16:44.854501
from pyarmor_runtime_000000 import __pyarmor__
__pyarmor__(__name__, __file__,
b'PY000000¥x00¥x03¥x0b¥x00¥xa7¥r¥r¥n¥x80¥x00¥x01¥x00¥x08
¥x00¥x00¥x00¥x04¥x00¥x00¥x00@¥x00¥x00¥x00¥xb9¥x0b¥x00¥x0
0¥x12¥t¥x04¥x00¥xe6¥x12¥xb4¥x7f2¥xb7[ ;5¥xb2¥xc0Rg¥x0ba¥
x00¥x00¥x00¥x00¥x00¥x00¥x00¥x00¥xc0¥x91¥xca1uF¥x93¥x98N¥
xaa¥x92Uh¥xe8¥x07Vo@¥xa2¥x04¥xe9¥xa7;¥x1eq¥xc5¥xc7¥x02¥x
e2¥x95¥xc7¥x12$3V?]¥xa5¥x05¥xe0¥x94¥x828¥x886D¥xaaY¥nS¥x
81G)Q¥xb8¥xcb¥xa4¥xff¥x86¥x03K¥x14S¥xa1¥x00¥x12¥x99[/¥x9
av¥x1dCa¥x1e¥xc7¥xa9¥xc3¥x9d¥xc97¥x16¥xbf¥x89¥xb6¥xaa¥xb
4¥xfdT¥r¥xe4WA?¥xc8N¥x83<S¥x9fZoU¥xcb5tf¥xa1¥xbe¥x07¥xf6
¥xd8¥x1b¥xec¥xec¥x8dx¥xe6¥x01¥xe6¥xb3¥x0e¥x18¥x9c¥xb1¥xc
4=¥x94¥xdd@¥xc5fH¥x9f¥xddR¥xc5¥x1ew"VL¥x9b¥xe2¥x93¥xdc¥x
db¥x0e¥xf4d¥x85u[¥xe0¥xcc¥xeaX¥x8e¥xf0¥xf1%¥x87¥xb3¥xb1¥
xa5¥x02¥xf1¥xaa¥x1e¥xf8¥xceL¥x8c¥x0e¥x1f¥x1c¥xe8¥xd2¥xcf
¥x1a¥x96F¥x13¥x02¥x01vdH¥xa6NU¥x18¥x14,h¥x18¥xe9¥x87¥x1f
{¥xa1¥xd9k¥xc4¥x98p¥xfd¥xd9GB{UtO¥x1f¥xd0¥xf4V¥x1aZ¥x11^
~¥xa4¥xa9?g¥xb2K¥xeec¥x05:¥xd7K¥xeb¥x14J¥xcb¥xb7¥xecC¥xd
a¥xbc¥xa2$¥x1d¥xb9¥xcc¥xdcy¥xaf¥x04¥x12¥xb6¥xf8¥x18¥xf8n
¥x8eY6¥x9f=¥xff¥x1eR¥xa1]V¥xb6?¥x0c¥¥¥xff¥x88-¥xbe¥x12
制約:付属ライブラリが必要
• OSやPythonのバージョンが
変わると実行できない
• dockerを使えば解決
• この制約はコンパイルと同じ
• pyarmorならライセンス期
限が来たら実行できなく
することもできる
世界一
読みにくいコード選手権
国際難読化Cコードコンテスト
nコードの読み難さを競うコ
ンテスト
• C言語限定
• Cは仕様が緩いからひど
いコードでもコンパイル
して実行できる
https://www.ioccc.org
https://www.ioccc.org/years.html#2020
Leo Broukhis, Simon Cooper, Landon
Curt Noll, CC BY-SA 3.0
2020 Winners
https://www.ioccc.org/2020/burton/prog.c
https://www.ioccc.org/2020/burton/index.html
int main(int b,char**i){long long n
=B,a=I^n,r=(a/b&a)>>4,y=atoi(*++i),
_=(((a^n/b)*(y>>T)|y>>S)&r)|(a^r);p
rintf("%.8s¥n",(char*)&_);}
2020 Winners
https://www.ioccc.org/2020/carlini/prog.c
https://www.ioccc.org/2020/carlini/index.html
#include <stdio.h>
#define N(a) "%"#a"$hhn"
#define O(a,b) "%10$"#a"d"N(b)
#define U "%10$.*37$d"
#define G(a) "%"#a"$s"
#define H(a,b) G(a)G(b)
#define T(a) a a
#define s(a) T(a)T(a)
#define A(a) s(a)T(a)a
#define n(a) A(a)a
#define D(a) n(a)A(a)
#define C(a) D(a)a
#define R C(C(N(12)G(12)))
#define o(a,b,c) C(H(a,a))D(G(a))C(H(b,b)G(b))n(G(b))O(32,c)R
#define SS O(78,55)R "¥n¥033[2J¥n%26$s";
#define E(a,b,c,d) H(a,b)G(c)O(253,11)R G(11)O(255,11)R H(11,d)N(d)O(253,35)R
#define S(a,b) O(254,11)H(a,b)N(68)R G(68)O(255,68)N(12)H(12,68)G(67)N(67)
char* fmt = O(10,39)N(40)N(41)N(42)N(43)N(66)N(69)N(24)O(22,65)O(5,70)O(8,44)N(
45)N(46)N (47)N(48)N( 49)N( 50)N( 51)N(52)N(53 )O( 28,
54)O(5, 55) O(2, 56)O(3,57)O( 4,58 )O(13, 73)O(4,
71 )N( 72)O (20,59 )N(60)N(61)N( 62)N (63)N (64)R R
E(1,2, 3,13 )E(4, 5,6,13)E(7,8,9 ,13)E(1,4 ,7,13)E
(2,5,8, 13)E( 3,6,9,13)E(1,5, 9,13)E(3 ,5,7,13
)E(14,15, 16,23) E(17,18,19,23)E( 20, 21, 22,23)E
(14,17,20,23)E(15, 18,21,23)E(16,19, 22 ,23)E( 14, 18,
22,23)E(16,18,20, 23)R U O(255 ,38)R G ( 38)O( 255,36)
R H(13,23)O(255, 11)R H(11,36) O(254 ,36) R G( 36 ) O(
255,36)R S(1,14 )S(2,15)S(3, 16)S(4, 17 )S (5, 18)S(6,
19)S(7,20)S(8, 21)S(9 ,22)H(13,23 )H(36, 67 )N(11)R
G(11)""O(255, 25 )R s(C(G(11) ))n (G( 11) )G(
11)N(54)R C( "aa") s(A( G(25)))T (G(25))N (69)R o
(14,1,26)o( 15, 2, 27)o (16,3,28 )o( 17,4, 29)o(18
,5,30)o(19 ,6,31)o( 20,7,32)o (21,8,33)o (22 ,9,
34)n(C(U) )N( 68)R H( 36,13)G(23) N(11)R C(D( G(11)))
D(G(11))G(68)N(68)R G(68)O(49,35)R H(13,23)G(67)N(11)R C(H(11,11)G(
11))A(G(11))C(H(36,36)G(36))s(G(36))O(32,58)R C(D(G(36)))A(G(36))SS
#define arg d+6,d+8,d+10,d+12,d+14,d+16,d+18,d+20,d+22,0,d+46,d+52,d+48,d+24,d¥
+26,d+28,d+30,d+32,d+34,d+36,d+38,d+40,d+50,(scanf(d+126,d+4),d+(6¥
-2)+18*(1-d[2]%2)+d[4]*2),d,d+66,d+68,d+70, d+78,d+80,d+82,d+90,d+¥
92,d+94,d+97,d+54,d[2],d+2,d+71,d+77,d+83,d+89,d+95,d+72,d+73,d+74¥
,d+75,d+76,d+84,d+85,d+86,d+87,d+88,d+100,d+101,d+96,d+102,d+99,d+¥
67,d+69,d+79,d+81,d+91,d+93,d+98,d+103,d+58,d+60,d+98,d+126,d+127,¥
d+128,d+129
char d[538] = {1,0,10,0,10};
int main() {
while(*d) printf(fmt, arg);
}
2020 Winners
https://www.ioccc.org/2020/endoh1/prog.c
https://www.ioccc.org/2020/endoh1/index.html
#include/**/<time.h>
#include <ncurses.h>
# include <stdlib.h>
/** */#define O()for(y-= !!¥
y;y<H&& /*...Semi-Automatic.*/y< p/W+2;¥
y++)for(x=p% W,x-=!!/*..MineSweeper...*/x;x<W&& x<p%W+2;x++)
#define _(x,y)COLOR_##x,COLOR_##y /* click / (R)estart / (Q)uit */
#define Y(n)attrset(COLOR_PAIR(n)),mvprintw(/* IOCCC2019 or IOCCC2020 */
typedef int I;I*M,W,H,S,C,E,X,T,c,p,q,i,j,k;char G[]=" x",U[256];I F(I p){ I
r=0,x,y=p/W,q;O()q=y*W+x,r+=M[q]^=p-q?(M[q]&16)<<8:0;return r;}I K(I p
,I f,I g){ I x=(g+ f/256)%16-(f+g/256)%16,y=p/W,c=0,n=g/4096
,m=x==n?0:x==g /16%16-f/16%16-n?256:-1; if(m+1)O()if
((4368&M[n=y*W +x])==4112){ M[c=1,n]=(M[n]&~16)|m; }
return c;}void D(){I p,k,o=0,n=C,m=0,q=0;if(LINES-1<H
||COLS/2<W)clear (),Y(4)LINES/2,COLS/2-16,"Make the ter¥
minal bigger!");else{for (p=0;p<S;o+=k==3,Y(k)p/W+1,p%W*2,G),p++)G[1]=""
"_*!..12345678"[k=E?256&M[p ]?n--,2:E-2||M[p]%2<1?M[p]&16?q=p,m++,3:4+F(p)%16:
1:3];k=T+time(0);T=o||T>=0||E-1?T:k;k=T<0?k:T;Y(7)0,0,"%03d%*s%03d",n>999?999:n,W*
2-6,"",k>999?999:k);Y(9)0,W-1,E>1?"X-(":E-1||o?":-)":"8-)");M[q]|=256*(n==m&&n); }
refresh();}short B[]={_(RED,BLACK),_(WHITE,BLUE),_(GREEN,RED),_(MAGENTA,YELLOW),_(
CYAN,RED)};I main(I A,char**V){MEVENT e;FILE*f;srand(time(0));initscr();for(start¥
_color();X<12;X++){init_pair(X+1,B[X&&X<10?X-1:2],B[X?X<3?2:1:0]);}noecho();cbreak
();timeout(9);curs_set(0);keypad(stdscr,TRUE);for(mousemask(BUTTON1_CLICKED|BUTTO¥
N1_RELEASED,0);;){S=A<2?f=0,W=COLS/2,H=LINES-1,C=W*H/5,0:fscanf(f=fopen(V[A-1],"r"
),"%d %d %d",&W,&H,&C)>3; ;S+=W*H;M=realloc(M,S*sizeof(I)*2);for(i=0
;i<S;i++)!f?M[i]=i,i&&(k=M[j=rand()%i],M[j]=M[i],M[i]=k):fscanf(f,
"%d",M+i);if(f)fclose(f);T=E=X=0;for(clear();D(),c=getch(),c-'r'
&&(c-KEY_RESIZE||E);){ if(c=='q'){ return(endwin(),0); }if(c==
KEY_MOUSE&&getmouse(&e)==OK&&e.x/2<W&&e.y<=H){if(!e.y&&(W-2<e.x&&
e.x<W+2)){break;}p=e.x/2+e.y*W-W;if(p>=0){if(!E){for(i=0;i<S;i++)M[S+M
[i]]=i,M[i]=16+(M[i]<C);C-=M[p]&1;M[p]=16;E=1;T=-time(0);}if(E<2)M[p]&=(M[p]
&257)==1?T+=time(0),E=2,273:257;}}for(p=0;p<S&&E==1;M[p++]&=273){}for(i=
(X+S-1)%S;E==1&&i!=X;X=(X+1)%S){if(!(M[p=M[X+S]]&272)){if(K(p,c=F(p)
,0)){goto N;} for(k=p/W-2,k=k<0?0:k;k<p/W+3&&k <H;k++)for(j=
p%W-2,j =j<0?0:j;j<W&&j<p%W+3;)if (!(M[q=
k*W +j++]&272)){ if(K(p, c,F
(q))){ goto N; }F(q)
; }F(p); }}N:; } } }
/*(c)Yusukse Endoh*/
Winner vs formatter
#include /**/ < time.h >
#include <ncurses.h>
#include <stdlib.h>
/** */ #define O() for (
y -= !!y; y < H && /*...Semi-Automatic.*/ y < p / W + 2;
y++) for (x = p % W, x -= !!/*..MineSweeper...*/ x; x < W && x < p % W + 2;
x++)
#define _(x, y) COLOR_##x, COLOR_##y /* click / (R)estart / (Q)uit */
#define Y(n)attrset(COLOR_PAIR(n)),mvprintw(/* IOCCC2019 or IOCCC2020 */
typedef int I;
I *M, W, H, S, C, E, X, T, c, p, q, i, j, k;
char G[] = " x", U[256];
I F(I p) {
I r = 0, x, y = p / W, q;
O()
q = y * W + x, r += M[q] ^= p - q ? (M[q] & 16) << 8 : 0;
return r;
}
I K(I p, I f, I g) {
I x = (g + f / 256) % 16 - (f + g / 256) % 16, y = p / W, c = 0, n = g / 4096,
m = x == n ? 0 : x == g / 16 % 16 - f / 16 % 16 - n ? 256 : -1;
if (m + 1) O()
if ((4368 & M[n = y * W + x]) == 4112) {
M[c = 1, n] = (M[n] & ~16) | m;
}
return c;
}
void D() {
I p, k, o = 0, n = C, m = 0, q = 0;
if (LINES - 1 < H || COLS / 2 < W)clear (),Y(4)LINES/2,COLS/2-16,"Make the ter¥
minal bigger!");
else {
for (p = 0; p < S; o += k == 3, Y(k) p / W + 1, p % W * 2, G),p++)G[1]=""
"_*!..12345678"[k=E?256&M[p ]?n--,2:E-2||M[p]%2<1?M[p]&16?q=p,m++,3:4+F(p)%16:
1:3];
k = T + time(0);
T = o || T >= 0 || E - 1 ? T : k;
k = T < 0 ? k : T;Y(7)0,0,"%03d%*s%03d",n>999?999:n,W*
2-6,"",k>999?999:k);Y(9)0,W-1,E>1?"X-(":E-1||o?":-)":"8-)");
M[q] |= 256 * (n == m && n);
}
refresh();
}
short B[] = {_(RED, BLACK), _(WHITE, BLUE), _(GREEN, RED), _(MAGENTA, YELLOW),
_(CYAN, RED)};
I main(I A, char** V) {
https://github.com/KrzaQ/cppformat
http://format.krzaq.cc
でGoogleスタイルへフォーマット
したら...
無理なものは無理
#include/**/<time.h>
#include <ncurses.h>
# include <stdlib.h>
/** */#define O()for(y-= !!¥
y;y<H&& /*...Semi-Automatic.*/y< p/W+2;¥
y++)for(x=p% W,x-=!!/*..MineSweeper...*/x;x<W&& x<p%W+2;x++)
#define _(x,y)COLOR_##x,COLOR_##y /* click / (R)estart / (Q)uit */
#define Y(n)attrset(COLOR_PAIR(n)),mvprintw(/* IOCCC2019 or IOCCC2020 */
typedef int I;I*M,W,H,S,C,E,X,T,c,p,q,i,j,k;char G[]=" x",U[256];I F(I p){ I
r=0,x,y=p/W,q;O()q=y*W+x,r+=M[q]^=p-q?(M[q]&16)<<8:0;return r;}I K(I p
,I f,I g){ I x=(g+ f/256)%16-(f+g/256)%16,y=p/W,c=0,n=g/4096
,m=x==n?0:x==g /16%16-f/16%16-n?256:-1; if(m+1)O()if
((4368&M[n=y*W +x])==4112){ M[c=1,n]=(M[n]&~16)|m; }
return c;}void D(){I p,k,o=0,n=C,m=0,q=0;if(LINES-1<H
||COLS/2<W)clear (),Y(4)LINES/2,COLS/2-16,"Make the ter¥
minal bigger!");else{for (p=0;p<S;o+=k==3,Y(k)p/W+1,p%W*2,G),p++)G[1]=""
"_*!..12345678"[k=E?256&M[p ]?n--,2:E-2||M[p]%2<1?M[p]&16?q=p,m++,3:4+F(p)%16:
1:3];k=T+time(0);T=o||T>=0||E-1?T:k;k=T<0?k:T;Y(7)0,0,"%03d%*s%03d",n>999?999:n,W*
2-6,"",k>999?999:k);Y(9)0,W-1,E>1?"X-(":E-1||o?":-)":"8-)");M[q]|=256*(n==m&&n); }
refresh();}short B[]={_(RED,BLACK),_(WHITE,BLUE),_(GREEN,RED),_(MAGENTA,YELLOW),_(
CYAN,RED)};I main(I A,char**V){MEVENT e;FILE*f;srand(time(0));initscr();for(start¥
_color();X<12;X++){init_pair(X+1,B[X&&X<10?X-1:2],B[X?X<3?2:1:0]);}noecho();cbreak
();timeout(9);curs_set(0);keypad(stdscr,TRUE);for(mousemask(BUTTON1_CLICKED|BUTTO¥
N1_RELEASED,0);;){S=A<2?f=0,W=COLS/2,H=LINES-1,C=W*H/5,0:fscanf(f=fopen(V[A-1],"r"
),"%d %d %d",&W,&H,&C)>3; ;S+=W*H;M=realloc(M,S*sizeof(I)*2);for(i=0
;i<S;i++)!f?M[i]=i,i&&(k=M[j=rand()%i],M[j]=M[i],M[i]=k):fscanf(f,
"%d",M+i);if(f)fclose(f);T=E=X=0;for(clear();D(),c=getch(),c-'r'
&&(c-KEY_RESIZE||E);){ if(c=='q'){ return(endwin(),0); }if(c==
KEY_MOUSE&&getmouse(&e)==OK&&e.x/2<W&&e.y<=H){if(!e.y&&(W-2<e.x&&
e.x<W+2)){break;}p=e.x/2+e.y*W-W;if(p>=0){if(!E){for(i=0;i<S;i++)M[S+M
[i]]=i,M[i]=16+(M[i]<C);C-=M[p]&1;M[p]=16;E=1;T=-time(0);}if(E<2)M[p]&=(M[p]
&257)==1?T+=time(0),E=2,273:257;}}for(p=0;p<S&&E==1;M[p++]&=273){}for(i=
(X+S-1)%S;E==1&&i!=X;X=(X+1)%S){if(!(M[p=M[X+S]]&272)){if(K(p,c=F(p)
,0)){goto N;} for(k=p/W-2,k=k<0?0:k;k<p/W+3&&k <H;k++)for(j=
p%W-2,j =j<0?0:j;j<W&&j<p%W+3;)if (!(M[q=
k*W +j++]&272)){ if(K(p, c,F
(q))){ goto N; }F(q)
; }F(p); }}N:; } } }
/*(c)Yusukse Endoh*/
ソフトウェア工学2023 12 コードフォーマット
課題
n自分の過去に書いたコードがどの
ような規約に従っていたか,もし
くは従っていなかったか,を具体
例を上げて説明する
nそのコードに対して規約に準拠し
たコードに修正する
• 変数名は手動で修正
• python以外の言語は何らかのフォー
マッタを利用(使用したツール・サ
イトを明記すること)
• Java
• https://www.tutorialspoint.com
/online_java_formatter.htm
• https://codebeautify.org/javavi
ewer
• https://jsonformatter.org/java-
formatter
• C/C++
• https://www.tutorialspoint.com
/online_c_formatter.htm
• http://format.krzaq.cc
• https://codebeautify.org/cpp-
formatter-beautifier
• Perl
• https://www.tutorialspoint.com
/online_perl_formatter.htm
想定試験問題
nコーディング規約とは何か,その重要性を説明せよ
nコーディング規約の例を具体例を上げて説明せよ
n変数の命名規則にはどのようなものがあるのか,具体例を上げて説明
せよ
nPEP8で指定されているインデント・空白文字・命名規約の使い方は
何かを説明せよ
nflake8やautopep8の使い方を説明せよ
n難読化とは何か,その必要性と,難読化しない場合に生じる問題を説
明せよ

More Related Content

PDF
Introduction to Agile - how business and engineer team up
PPTX
Agile開発でのテストのやり方~私の場合~
PDF
SES2020 IoTアーキテクチャ・デザインパターン
PDF
ソフトウェアパターン概論およびパターンを活用したアーキテクチャ設計
PPTX
スケールアウトするPostgreSQLを目指して!その第一歩!(NTTデータ テクノロジーカンファレンス 2020 発表資料)
PPTX
PHP と SAPI と ZendEngine3 と
PDF
Djangoのエントリポイントとアプリケーションの仕組み
PPTX
Memcachedの仕組みと設定
Introduction to Agile - how business and engineer team up
Agile開発でのテストのやり方~私の場合~
SES2020 IoTアーキテクチャ・デザインパターン
ソフトウェアパターン概論およびパターンを活用したアーキテクチャ設計
スケールアウトするPostgreSQLを目指して!その第一歩!(NTTデータ テクノロジーカンファレンス 2020 発表資料)
PHP と SAPI と ZendEngine3 と
Djangoのエントリポイントとアプリケーションの仕組み
Memcachedの仕組みと設定

What's hot (20)

PDF
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
PDF
「自分のとこでは動くけど…」を無くす devcontainer
PDF
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
PDF
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
PDF
いつやるの?Git入門 v1.1.0
PDF
人生がときめくAPIテスト自動化 with Karate
PDF
【マーケティング・テクノロジーフェア 大阪 2023】 データから正しい意思決定を行うために 〜全社横断で実施したデータ活用プロジェクトの取...
PPTX
PostgreSQL 12は ここがスゴイ! ~性能改善やpluggable storage engineなどの新機能を徹底解説~ (NTTデータ テクノ...
PDF
モジュールの凝集度・結合度・インタフェース
KEY
バージョン管理のワークフロー
PPTX
プロジェクトマネージャのための機械学習工学入門
PDF
PyData.Tokyo Meetup #21 講演資料「Optuna ハイパーパラメータ最適化フレームワーク」太田 健
PDF
Webアプリを並行開発する際のマイグレーション戦略
PDF
Lean coffee
PPTX
5分で分かる自己組織化マップ
PDF
『ラブライブ!スクールアイドルフェスティバル ALL STARS』を支えるビルドパイプライン 〜より安定したサービス提供を目指して〜
PDF
ゼロ幅スペースという悪夢
PDF
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
PPTX
分散システムについて語らせてくれ
PDF
マルチAIエージェントと最近の取り組み Multi AI agent and Some recent research topics
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
「自分のとこでは動くけど…」を無くす devcontainer
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
いつやるの?Git入門 v1.1.0
人生がときめくAPIテスト自動化 with Karate
【マーケティング・テクノロジーフェア 大阪 2023】 データから正しい意思決定を行うために 〜全社横断で実施したデータ活用プロジェクトの取...
PostgreSQL 12は ここがスゴイ! ~性能改善やpluggable storage engineなどの新機能を徹底解説~ (NTTデータ テクノ...
モジュールの凝集度・結合度・インタフェース
バージョン管理のワークフロー
プロジェクトマネージャのための機械学習工学入門
PyData.Tokyo Meetup #21 講演資料「Optuna ハイパーパラメータ最適化フレームワーク」太田 健
Webアプリを並行開発する際のマイグレーション戦略
Lean coffee
5分で分かる自己組織化マップ
『ラブライブ!スクールアイドルフェスティバル ALL STARS』を支えるビルドパイプライン 〜より安定したサービス提供を目指して〜
ゼロ幅スペースという悪夢
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
分散システムについて語らせてくれ
マルチAIエージェントと最近の取り組み Multi AI agent and Some recent research topics
Ad

Similar to ソフトウェア工学2023 12 コードフォーマット (20)

PDF
Pythonで始めるDropboxAPI
PDF
第3回yidev coding guideline読み
PPTX
Ruby講座一回目
PPTX
Ruby講座一回目
PDF
Ruby4章後半(演算子)
PDF
PEP8を読んでみよう
PPT
Pythonintro
PDF
プログラミング入門
PDF
プログラミング言語 Ruby 2章 Rubyプログラムの構造と実行
PDF
Good coding for research
PDF
Oss coding style
PDF
Ruby紹介(pdf)
PDF
Processing
PDF
#5:プログラミングの基本
PDF
入れ子構造を分解する
PDF
C-HelperでC言語を効率的に学習しよう
PDF
良い?悪い?コードコメントの書き方
PPTX
Python 学習教材
PDF
Python勉強会2-数値と文字列
Pythonで始めるDropboxAPI
第3回yidev coding guideline読み
Ruby講座一回目
Ruby講座一回目
Ruby4章後半(演算子)
PEP8を読んでみよう
Pythonintro
プログラミング入門
プログラミング言語 Ruby 2章 Rubyプログラムの構造と実行
Good coding for research
Oss coding style
Ruby紹介(pdf)
Processing
#5:プログラミングの基本
入れ子構造を分解する
C-HelperでC言語を効率的に学習しよう
良い?悪い?コードコメントの書き方
Python 学習教材
Python勉強会2-数値と文字列
Ad

More from Toru Tamaki (20)

PDF
論文紹介:Unboxed: Geometrically and Temporally Consistent Video Outpainting
PDF
論文紹介:OVO-Bench: How Far is Your Video-LLMs from Real-World Online Video​ Unde...
PDF
論文紹介:HOTR: End-to-End Human-Object Interaction Detection​ With Transformers, ...
PDF
論文紹介:Segment Anything, SAM2: Segment Anything in Images and Videos
PDF
論文紹介:Unbiasing through Textual Descriptions: Mitigating Representation Bias i...
PDF
論文紹介:AutoPrompt: Eliciting Knowledge from Language Models with Automatically ...
PDF
論文紹介:「Amodal Completion via Progressive Mixed Context Diffusion」「Amodal Insta...
PDF
論文紹介:「mPLUG-Owl3: Towards Long Image-Sequence Understanding in Multi-Modal La...
PDF
論文紹介:What, when, and where? ​Self-Supervised Spatio-Temporal Grounding​in Unt...
PDF
論文紹介:PitcherNet: Powering the Moneyball Evolution in Baseball Video Analytics
PDF
論文紹介:"Visual Genome:Connecting Language and Vision​Using Crowdsourced Dense I...
PDF
論文紹介:"InfLoRA: Interference-Free Low-Rank Adaptation for Continual Learning" ...
PDF
論文紹介:ActionSwitch: Class-agnostic Detection of Simultaneous Actions in Stream...
PDF
論文紹介:Make Pixels Dance: High-Dynamic Video Generation
PDF
PCSJ-IMPS2024招待講演「動作認識と動画像符号化」2024年度画像符号化シンポジウム(PCSJ 2024) 2024年度映像メディア処理シンポジ...
PDF
論文紹介:T-DEED: Temporal-Discriminability Enhancer Encoder-Decoder for Precise E...
PDF
論文紹介:On Feature Normalization and Data Augmentation
PDF
論文紹介:CLIFF: Continual Latent Diffusion for Open-Vocabulary Object Detection
PDF
論文紹介:MS-DETR: Efficient DETR Training with Mixed Supervision
PDF
論文紹介:Synergy of Sight and Semantics: Visual Intention Understanding with CLIP
論文紹介:Unboxed: Geometrically and Temporally Consistent Video Outpainting
論文紹介:OVO-Bench: How Far is Your Video-LLMs from Real-World Online Video​ Unde...
論文紹介:HOTR: End-to-End Human-Object Interaction Detection​ With Transformers, ...
論文紹介:Segment Anything, SAM2: Segment Anything in Images and Videos
論文紹介:Unbiasing through Textual Descriptions: Mitigating Representation Bias i...
論文紹介:AutoPrompt: Eliciting Knowledge from Language Models with Automatically ...
論文紹介:「Amodal Completion via Progressive Mixed Context Diffusion」「Amodal Insta...
論文紹介:「mPLUG-Owl3: Towards Long Image-Sequence Understanding in Multi-Modal La...
論文紹介:What, when, and where? ​Self-Supervised Spatio-Temporal Grounding​in Unt...
論文紹介:PitcherNet: Powering the Moneyball Evolution in Baseball Video Analytics
論文紹介:"Visual Genome:Connecting Language and Vision​Using Crowdsourced Dense I...
論文紹介:"InfLoRA: Interference-Free Low-Rank Adaptation for Continual Learning" ...
論文紹介:ActionSwitch: Class-agnostic Detection of Simultaneous Actions in Stream...
論文紹介:Make Pixels Dance: High-Dynamic Video Generation
PCSJ-IMPS2024招待講演「動作認識と動画像符号化」2024年度画像符号化シンポジウム(PCSJ 2024) 2024年度映像メディア処理シンポジ...
論文紹介:T-DEED: Temporal-Discriminability Enhancer Encoder-Decoder for Precise E...
論文紹介:On Feature Normalization and Data Augmentation
論文紹介:CLIFF: Continual Latent Diffusion for Open-Vocabulary Object Detection
論文紹介:MS-DETR: Efficient DETR Training with Mixed Supervision
論文紹介:Synergy of Sight and Semantics: Visual Intention Understanding with CLIP

ソフトウェア工学2023 12 コードフォーマット