質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.13%

アセンブリプログラムの解説

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 4
  • VIEW 1,616

carnage0216

score 129

アセンブリ言語のプルグラムに関する質問です。
ある本でアセンブリを勉強をしているのですがわからない部分があります。
横幅が4の倍数協会にない場合のダミーデータを計算するようなのですが、
なぜダミーデータを計算するのかわかりません。
横幅が4倍でない場合にレジスタと演算回路で計算して4で割り切れない場合の余りを捨てるという意味でしょうか?というかアセンブリプログラムはそのように書いてあるのでしょうか?
個人的に4倍ではなく1バイトが8bitなので8で割ったほうが都合がよいように思えますが。

計算部分とアセンブリ言語のプログラムのある部分に疑問があります。
以上について質問します。疑問のある部分に丸で囲んだ数字を置きます。

wMargineをゼロクリアにして、widthをeaxレジスタに代入します。
4で割った余りを算出するためにeaxレジスタを3で論理積を行う。
(⓵ここで3倍した理由は4で割った際の余りが3以上になるようにするためですか?
だとしたらもともとダミーデータが出ないように計算したほうがいいように思えますが。)
最下位2bitのいずれかが立っているかを検査します。
もし、4で割ったときに余りがあったら、widthを3倍し、それを4で割って得る。そして4から余りを引いてwMargineに設定する。
(⓶「そして4から余りを引いてwMargineに設定する。」の部分の4から余りを引く理由がわかりません)

プログラム通りeaxレジスタにwidthを入れます。そしてebxレジスタに3を代入し乗算します。
(⓷eaxレジスタとebxレジスタを乗算するのはわかるのですがプログラムにはmul ebxとしか書いていないのですが、なぜmul ebxと書いただけでeaxレジスタとebxレジスタを乗算する結果がebxに入る理由がわかりません。演算結果を一旦別のレジスタに入れた後に、mov命令でebxに演算結果をいれるならば理解できます。このアセンブリプログラムを出力したCPUの構造故にmul ebxと書いただけでeaxレジスタとebxレジスタの乗算結果がebxに入るのでしょうか?だとしたら仕方ないです。)

その後4バイトの乗算であるため上位4バイトがedxと下位4バイトがeaxレジスタへ代入されるようです
(⓸この乗算結果を二つのレジスタに乗算の結果を分割して入れている命令部分はプログラムのどこに書いてあるのでしょうか?
どのようにアセンブリ命令を書くことで分割してレジスタに入れられたのでしょうか?)

最後にダミーデータを知るために下位4バイトを入れたeaxレジスタと0x00000003で乗算して余りを取得したと書いてあります。これでダミーデータが得られたそうですが、なぜ得られたのか解説をよんでもいまいちわかりません。(⓹下位4バイトを入れたeaxレジスタと0x00000003で乗算して余りを取得したと書いてあります。これでダミーデータが得られた理由がわかりません。また何で割ったのかわからないのですがアセンブリプログラムには書いてあるでしょうか?)

プログラムは以下の通りです。

mov        wMargine, 0
        mov        eax, width            /* 幅        */
        and        eax, 0x00000003        /* %4            */
        jz        no_margin

        xor        edx, edx            /* クリア        */
        mov        eax, width            /* 幅            */
        mov        ebx, 3                /* 3            */
        mul        ebx                    /* 幅x 3        */
        and        eax, 0x00000003        /* %4            */
        mov        ebx, 4                /* 4            */
        sub        ebx, eax
        mov        wMargine, ebx

以上5つの質問でありますが、どうか解説して頂けると大変助かります。
C言語を勉強している上でより技術を磨くためにアセンブリ言語を身に着けたいと思います。
どうかよろしくお願いいたします。

修正
論理積と足し算を勘違いして使っていました。
ようやく回答者様の皆様の回答が理解できてきました。
以後できる限り気を付けて質問します。
どうかよろしくお願いいたします。
本当に申し訳ありませんでした。

3/19 復習している際に疑問が出来たので再度以下の事に関して質問したいのですが、ここでは書きにくいため新しく質問を作ります。回答していただけると大変ありがたいです。
一時的に質問をしないとのことでしたが今回に関してはどうかお許しください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+4

おそらくビットマップの仕様

水平方向のバイト数が4の倍数ではないときは、0x00で埋めて4の倍数にする。

です。(なんか他にもavi/jpg/png/gif/mpegの仕様で幅に制限あるフォーマットがあった気がするけど思い出せない)

個人的に4倍ではなく1バイトが8bitなので8で割ったほうが都合がよいように思えますが。

1bitには0か1の情報しか詰められませんけど、モノクロ画像でしょうか?

 > ⓵ここで3倍した理由は4で割った際の余りが3以上になるようにするためですか? 

24bit bmpなのでは?

 > ⓶「そして4から余りを引いてwMargineに設定する。」の部分の4から余りを引く理由がわかりません

目的はwidth * 3 + wMargine== 4の倍数にしたいのです。
wMargineが1~4とした場合

n = width * 3 / 4
width * 3 + wMargine= 4 * (n + 1)


この連立方程式を解いてください

編集:計算するとおかしかったので追記
数の性質です。 
ある数nの4で割った余りが

  • 1の時、n+3は4で割り切れる
  • 2の時、n+2は4で割り切れる
  • 3の時、n+1は4で割り切れる
  • 0の時、nは4で割り切れる

 > ⓷eaxレジスタとebxレジスタを乗算するのはわかるのですがプログラムにはmul ebxとしか書いていない

 > ⓸この乗算結果を二つのレジスタに乗算の結果を分割して入れている命令部分はプログラムのどこに書いてあるのでしょうか?

以前の回答でx86_64の仕様書を貼り付けましたので割愛
不明な命令くらい自分で調べましょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/06 17:00

    んなわけで、こんな"こゆい"ネタに反応できる回答者の多くは間違いなくオッサンです。
    # そろそろ定年が見えてきたなァ...

    キャンセル

  • 2018/03/06 17:13

    そうなんですか‥‥。
    でもこゆいネタも私にとっては大変勉強になります。
    解説、どうもありがとうございました。

    キャンセル

  • 2018/03/06 17:57

    もしくは単に「先頭32bitに合わせてサイズも32bitに合わせる事を約束しておけばmemcpyが速い」ってだけかもね
    なんせwindows黎明期のフォーマットなので今とは事情が異なる可能性も大いにあります。

    キャンセル

+3

解決済ですが、diracpaulさんへの質問者のコメントには答えたいことがあります。

載せたアセンブラプログラミング以外のアセンブリ命令の組み合わせでも同じような処理を実現できるのでしょうか

アセンブリコードには決まりきった命令順(イディオムも)もよく出現しますが、そもそも命令の粒度が細かいので、人によって・コンパイラによって、同じ処理でもコードの違いは大きくなります。以下、コメントにC言語風の擬似命令を併記しながら解説します。

    xor   edx, edx      // edx ^= edx;
    mov   edx, 0        // edx = 0;
    sub   edx, edx      // edx -= edx;


既にご存知でしょう、これは3つ共にレジスタedxの0クリアが目的ですから、
mov edx, 0 が自然ですが、これだと32bitの0という値を機械語に持つため、機械語命令が長くなる・遅いかもしれない(アセンブルリストで機械語の違いを確認しましょう)、そこで2進数の性質を利用してxor命令がよく使われます。

edxには乗算の結果が格納されることから、おそらく安全のため0クリアした・・・宣言した変数はすべて0に初期化するのと同じ気持ちなのでしょう。でもmul命令の仕様がわかっていれば、edx を0にする必要が無いことは明らか。即ち、xor命令は削除できます。

次に乗算命令の箇所。

    mov    eax, width     // eax = width;
    mov    ebx, 3         // ebx = 3;
    mul    ebx            // edx:eax = eax * ebx;


32bit * 32bit の計算結果は 64bit になります。mul命令の結果が EDX:EAX に格納される(EDX, EAX レジスタを固定的に使う)ことから、乗数を EDX に入れて乗算させることが多いのではないでしょうか。レジスタは限りある資源なので、関数の中で使うレジスタを減らした方が何かと有利なのです。
どうせ mul 命令は edx を使うのだから、私ならここは edx を使い回します。ebx を使わずに済む事は大きいのです。こんな風に

    mov    eax, width     // eax = width;
    mov    edx, 3         // edx = 3;
    mul    edx            // edx:eax = eax * edx;
    ...                   // 途中省略
    mov    edx, 4
    sub    edx, eax       // edx = 4 - (width * 3) % 4;


それはともかく、3倍は同じ値を3つ足してもよいので、例えばこうできる。

    mov    eax, width     // eax = width;
    mov    edx, eax       // edx = eax;
    add    eax, edx       // eax += edx;  // width * 2
    add    eax, edx       // eax += edx;  // width * 3


mulは時間がかかる命令ですから、一命令増えても実行速度は断然速いです。
じゃあ10倍するには10回加算を繰り返すかというと、そうではなくて、2のべき乗(2, 4, 8, 16 ...)倍にシフト命令を使えることをご存知でしょう。10倍は8倍+2倍だから、10倍するマクロは

    #define MultBy10(x)  ((x) << 3 + (x) << 1)


のように、シフトと加算の組み合わせで実現できます。もっとも今のコンパイラは何もしなくても大抵こんな風に最適化しますが、アセンブリ言語ならどう書けばよいか、質問者への課題にしましょうか笑。

さて、ここが重要。
提示されたアセンブリコードは何を計算しているのか。全体をC言語風に書けば、こうなります。

    wMargine = 0;
    if ((width % 4) == 0) goto no_margin;
    wMargine = 4 - ((width * 3) % 4);     // この計算は何か?


width から wMargine を求めていることがわかります(と共に処理を分岐している)が、width % 4 は 0, 1, 2, 3 しかなく、0の場合は明らかなので、0以外を場合分けして考えると、計算結果はこうなります。

width%4  width   width*3 (width*3)%4  4-(width*3)%4
1    4n + 1   12n + 3    3     1
2    4n + 2   12n + 6    2     2
3    4n + 3   12n + 9    1     3

「width % 4」と「4 - ((width * 3) % 4)」が一致する!・・・実は乗算も減算も不要、即ちあの部分は無駄なコードなのです(あくまで提示されているコードを見る限りですが)。つまり、次の5行だけが残る。

    mov    wMargine, 0      // wMargine = 0;
    mov    eax, width       // eax = width;
    and    eax, 0x00000003  // eax %= 4;
    jz     no_margin        // if (eax == 0) goto no_margin;
    mov    wMargine, eax    // wMargine = eax;


さらに、x86はmov命令でフラグレジスタが変化しないので、次の4行まで絞り込める・・・

    mov    eax, width 
    and    eax, 0x00000003 // eax = width % 4;
    mov    wMargine, eax   // wMargine = width % 4;
    jz     no_margin       // if (eax == 0) goto no_margin;


このような「無駄」はアセンブリ言語に限った事ではありません。言い換えれば、漫然とコードを書くなら、どんな言語を使っても無駄な計算をしたり効率が悪かったりするという戒めになるでしょう。


wMargine = 4 - ((width * 3) % 4);     // この計算は何か?

念の為、この部分はどういうコードであったか。C言語風コメントをつけておきます。

    xor   edx, edx      // edx = 0;        (削除可能な命令)

    mov   eax, width    // eax = width;
    mov   ebx, 3        // ebx = 3;
    mul   ebx           // edx:eax = eax * ebx; 即ち edx:eax = width * 3;

    and   eax, 3        // eax &= 3; は eax %= 4; と同じ

    mov   ebx, 4        // ebx = 4;
    sub   ebx, eax      // ebx -= eax; 即ち ebx = 4 - ((width * 3) % 4);

    mov   wMargine, ebx // wMargine = ebx;

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/23 21:28 編集

    #include <stdio.h>
    main() {
    int w = 15;
    printf ("%d\n", (w * 3) );
    int i = (w * 3);
    printf ("%d\n", (w * 3)/4 );
    int a = (w * 3)/4 ;
    printf ("%d\n", (w * 3)%4 );
    }
    を実行したところ
    以下のように出ました。もちろん理解できた通り、11バイトあまり1バイトとでました。

    45
    11
    1

    キャンセル

  • 2018/03/23 21:30

    なるほど、「%」だとあまりが
    「/」 とすると11を得られるのですね。
    勉強不足でした。申し訳ありません。

    キャンセル

  • 2018/03/24 13:57

    あの、不快な解答をしてしまい申し訳ありません。
    私の回答は間違っているのでしょうか。
    %を/にしたところちゃんと4バイトが11個あることがわかりました。

    キャンセル

+2

寝ておきたらほぼ終わってたが、とりあえず書いたので

 基礎の基礎

 1bitとは

2進数1桁の事であり、0か1のどちらかの状態を保存する記憶領域です

 1byteとは

(2008年以降)標準的には8bitです。


 論理積とは

 まずは1ビットの論理積

左辺 & 右辺 = 解

左辺 右辺
0 0 0
0 1 0
1 0 0
1 1 1

という1ビットの演算です
1ビットが入力され1ビットが返される演算の事を論理演算といいます
今現在のコンピューターというのは突き詰めるとこういった論理演算で全てが実装されています。

 次にビット毎の論理積

これを拡張して8bitの演算を考えます
例: 101 & 15

101 = 0x65 = 0b01100101
15  = 0x0F = 0b00001111
101 & 15   = 0b00000101


両辺ともにビットが立っているところのみ1になります。

 AND EAX, 3について考える

これはEAX &= 0b11;ということです
つまり、EAXを2進数表記にした際の最下位2bitのうち立っているビットのみを取り出すものです。

 割り算との関係

10進数である数を100で割ったあまりを考える際、下2桁を取り出しますよね?
2進数でも同じです。
0b10=2で割ったあまりが欲しい場合は最下位ビットが立っているなら1で0なら0なんです。
0b100=4で割ったあまりが欲しいならば最下位2bitが4で割ったあまりになるのです。

以上が、CPU関連で必要な前提知識


 %演算子

C言語における%演算子は割り算のあまりを計算する演算子です。
10÷3=3あまり1
なので
10%3=1
になります。
割り算というのはCPUの算術演算(普通の算数の演算)の中でも非常に遅くなるべく回避したいものなので
X%4を計算するときはbit毎の論理演算で代用するのが定石になります。



 今回のプログラムについて

ビットマップのフォーマットによるとbmpに保存されている幅情報の単位はピクセルです。
1ピクセル=1ドット=点1個と置き換えてもいいです。

bmpには何色使えるかでいくつかの種類があります。
今回対象にしているフォーマットは推測ですが24bpp
1ピクセルごとに24bit=3byte使うことで16777216色使えるフォーマットだと思います。

1行ごとに最低限必要なバイト数は3*width byteですが
これを4byteの倍数になるように0を付け加えなければいけません。

仮にwidth=31ピクセルの場合を考えます。
31*3=93byte = 93=4*23 + 1byteなので3byte足して1行ごとに96byteになります。
93から余りの1がパディング長なのではなく、96-93の3byteがパディング長なのです。

 どうでもいいこと

ピクセル配列に追加されるバイト列なので
ダミーデータというとピクセル単位で追加される事を個人的に想起します。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/05 02:13

    本当に本当にどうもありがとうございます。
    早速今から基礎をおさらいします。
    夜分遅い中本当にどうもありがとうございました。

    キャンセル

0

前の方が説明されているので、詳しくはお話しませんが、このコードは、単に4で割った余りを計算してwMarginにセットしているだけと思いますので、単にwidthに対して4で割った余りをセットするだけでも良いと思います。

ちなみに、アセンブラではコーディングでは、mulやdivや条件ジャンプは遅いので、高速処理をする場合には、極力避けるべきです。私はコンパイラーのコード生成部を実装していたことがありますが,2倍や4倍する場合などでは、mulを使う場合には、シフト命令を使っていました。
その意味からいうと、このコーディングでは高速化するには変えたほうが良いと思います。4で割った余りなら、単に0x03でAndすれば、1つの命令で済みます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/03 22:44

    回答ありがとうございます。
    ッということは載せたアセンブラプログラミング以外のアセンブリ命令の組み合わせでも同じような処理を実現できるのでしょうか? 
    勉強のため本とは違う形で結果のしょつ力が同じようなアセンブリプログラムを作りたいと考えています。

    キャンセル

  • 2018/03/04 05:53 編集

    そらできるわな、モノによるけど。
    かけ算はたし算の繰り返しやろ? mod 4 は and 3 やろ?

    キャンセル

  • 2018/03/04 23:46 編集

    あの本書のCPUの構造がわからないので同じような結果になるかはわからないのですが。自分なりにコードを書いてみました。結果としては同じような結果になると思いますでしょうか?
    mov eax, width  // eax = width;
    mov edx, 3  // edx = 3;
    mul edx   // edx:eax = eax * edx;
    がもともとのコードです。

    以下が私の書いたコードです。
    mov eax, width
    mov ebx ,3
    mul eax ,ebx //←こう書いた場合は掛け算の結果はeaxに入るのでしょうか?//
    mov ebx ,eax //eaxの内容をebxに入れます。//

    どうかよろしくお願いいたします。

    キャンセル

  • 2018/03/06 21:26 編集

    私自身は、定年過ぎのおっさんなので、インテル系の新しいCPUの詳しい動作はちょっとわかりません。また、マニュアルも捨ててしまっており確実にこれで大丈夫とは言い切れませんが、ご勘弁ください。
    掛け算の場合には、例えば、16bit同士の掛け算だった場合には、結果としては32bit必要となります。
    インテル系チップの場合は、乗算するレジスタが決まっている為、eaxレジスタとオペランドで指定したレジスタと掛け算をするように決まっている為、mul命令のオペランドにはeaxレジスタを指定しないものと思われます。
    インテル系チップの乗算に関するページがありました。下記のURLをご覧ください。
    http://wisdom.sakura.ne.jp/programming/asm/assembly11.html
    ちなみに、私は、APPLEIIに搭載されていた6502や、PC88のZ80,PC98のインテルの86までです。
    アセンブラプログミングの醍醐味というと、それぞれのCPUの特徴を加味して高速処理を実現することにあります。例えば、6502では、レジスタが非常に少ない欠点はあるもの先頭の256バイトのメモリに対するアクセスが早くレジスタの代わりに利用するとか、インテル系のチップではMOVSコマンド(Z80ではLDIR)を使って文字列転送が高速できる事などです。今は、インテル系のチップが主流ですが、昔はたくさんの種類があり大変面白かったです。

    なお、今回の元になったアセンブラプログラムで修正すべきと思う点は、
    mov ebx,3
    の部分です。なぜ3なのか、これはこれが1ピクセルのバイト数と思いますが、コメントでこの事をもっと明確に書いた方がよかったのではと思います。それであれば、意図にが明確になったのではと思います。

    キャンセル

0

あの本書のCPUの構造がわからないので同じような結果になるかはわからないのですが。自分なりにコードを書いてみました。結果としては同じような結果になると思いますでしょうか?
mov eax, width  // eax = width;
mov edx, 3  // edx = 3;
mul edx   // edx:eax = eax * edx;
がもともとのコードです。
  以下が私の書いたコードです。
mov eax, width
mov ebx ,3
mul eax ,ebx //←こう書いた場合は掛け算の結果はeaxに入るのでしょうか?//
mov ebx ,eax //eaxの内容をebxに入れます。//

あーめんどくせー 四の五の言わんとやってみろなんだが、
やり方知らんと手が出せんだろからC/C++内にアセンブリ書いて呼んでみたサンプル。

/*
  Visual C++ 32bit(x86)コンパイラで試すべし
 */

#include <iostream>
#include <cstdint>

uint32_t your_asm(uint32_t width) {
  uint32_t result;
  __asm {
    mov eax, width
    mov edx, 3
    mul edx
    mov result, eax
  }
  return result;
}

uint32_t  my_asm(uint32_t width) {
  uint32_t result;
  __asm {
    mov eax, width
    mov ebx, 3
/*  mul eax, ebx マチガイ */
    mul ebx
    mov ebx, eax
    mov result, ebx
  }
  return result;
}

int main() {
  using namespace std;
  for ( uint32_t i = 0; i < 10; ++i ) { 
    cout << i << '\t' << your_asm(i) << '\t' << my_asm(i) << endl;
  }
}

/* 実行結果
0       0       0
1       3       3
2       6       6
3       9       9
4       12      12
5       15      15
6       18      18
7       21      21
8       24      24
9       27      27
*/

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/05 21:33

    ベーシックc++とgccは扱い方が異なると思うので。

    キャンセル

  • 2018/03/05 21:46

    > epistemeさんの方が情報を見つけるのが速すぎるというか
    経験は人並み以上にありますからね。
    求めるものがどこにあるか、あらかたの見当がつくんです。
    見つけるのが速いんじゃなくて、近づくのが速いんだと思う。

    キャンセル

  • 2018/03/06 15:55

    そうなんですか。
    どこかの企業に勤めているエンジニアの方なのでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる