異常コードコンパイラオプションによって引き起こされます

1.問題

最近、ダークネット動的ライブラリを呼び出すときに、私は、ライブラリの内容は、内部に聞くことができない奇妙な質問に遭遇しましたが、慎重な調査はこれがために、我々はlibdarknet.a呼んであることが判明した後、印刷結果は、ライブラリ内に正常ですアドレスが表示されますのためにオフセットが生じ、-DGPUオプションを追加していないファイルをコンパイルするとき。

2.例

、より明確に表現するために、問題を回復するための簡単なコードを記述するために。

次のようにfun.h、読み取ります。

#include <iostream>
void get_res(struct RESULT *res_);
struct RESULT
{
    float *res;
#ifdef GPU
    float *res_gpu;
#endif
    int n;
    int c;
    int h;
    int w;
};

fun.cpp、主な機能は、ボディ構造の割り当てのメンバーを与えることです:

#include "fun.h"
void get_res(RESULT *res_)
{
    res_->res = (float*)malloc(10 * sizeof(float));
    for (int i = 0; i < 10; i++)
    {
        rs_->res[i] = i;
    }
    res_->n = 1;
    res_->c = 2;
    res_->h = 3;
    res_->w = 4;
}

動的ライブラリのコンパイル
g++ -fPIC -shared -g -DGPU -o libfun.so fun.cpp

動的ライブラリのコードを呼び出す書きます:

#include "fun.h"

int main(int argc, char **argv)
{
    struct RESULT *result = (struct RESULT*)malloc(sizeof(struct RESULT));
    get_res(result);
    std::cout << "n:" << result->n << std::endl;
    std::cout << "c:" << result->c << std::endl;
    std::cout << "h:" << result->h << std::endl;
    std::cout << "w:" << result->w << std::endl;
    return 0;
}

-DGPUオプションを使用してコンパイル最初のテストコード:g++ main.cpp -g -Ilib -Llib -lfun -Wl,-rpath lib -DGPU -o main
結果を見て:

./main
n:1
c:2
h:3
w:4

一貫した出力と期待。

次に、コンパイラオプション-DGPUを削除します。g++ main.cpp -g -Ilib -Llib -lfun -Wl,-rpath lib -o main

./main
n:0
c:0
h:1
w:2

結果を詳しく見ては一見hはワット、元々のnの一部であったとの結果がもともとCに所属して、根本的な理由は-DGPUが生じたオフセット対処する予定です、明らかに間違っています。私たちの推測を検証するためのコードをデバッグ以下。

gdb ./main
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...done.
(gdb) b 6
Breakpoint 1 at 0x400a14: file main.cpp, line 6.
(gdb) r
Starting program: /home/gcs/work/study/diy_cnn/code/compile_opt/main

Breakpoint 1, main (argc=1, argv=0x7fffffffe398) at main.cpp:6
6       get_res(result);
(gdb) p &result->n
$1 = (int *) 0x613c28
(gdb) p &result->c
$2 = (int *) 0x613c2c
(gdb) p &result->h
$3 = (int *) 0x613c30
(gdb) p &result->w
$4 = (int *) 0x613c34
(gdb) s
get_res (res_=0x613c20) at fun.cpp:5
5       res_->res = (float*)malloc(10 * sizeof(float));
(gdb) p &res_->n
$5 = (int *) 0x613c30
(gdb) p &res_->c
$6 = (int *) 0x613c34
(gdb) p &res_->h
$7 = (int *) 0x613c38
(gdb) p &res_->w
$8 = (int *) 0x613c3c
(gdb)

私たちのプリントアウトからアドレスがあるアドレスに対応するwは、時間の.so入る、N、Cの前に見つけることができます

n:0x613c28
c:0x613c2c
h:0x613c30
w:0x613c34

.soを入力した後、N、C、H、Wアドレスは次のようになります。

n:0x613c30
c:0x613c34
h:0x613c38
w:0x613c3c

構造に関連して追加のアドレス情報を印刷した後

以下のアドレスでライブラリ関数の結果変数に入る前に:

result------------------0x613c20
struct RESULT
{
    float *res;---------0x613c20
#ifdef GPU
    float *res_gpu;-----由于编译选项里没有定义,所以该变量无地址
#endif
    int n;--------------0x613c28
    int c;--------------0x613c2c
    int h;--------------0x613c30
    int w;--------------0x613c34
};

次のようにライブラリ関数を入力した後、変数のアドレスをres_:

res_--------------------0x613c20
struct RESULT
{
    float *res;---------0x613c20
#ifdef GPU
    float *res_gpu;-----0x613c28
#endif
    int n;--------------0x613c30
    int c;--------------0x613c34
    int h;--------------0x613c38
    int w;--------------0x613c3c
};

対照的にアドレスした後、我々は利用価値の0x613c28アドレスは、単に動的ライブラリ内のアドレスの割り当てが見つからない場合は、つまり、nの値を取得しようとしたとき、すでに明らかとても自然に取得され、期待される結果は同じで、Cではありません同じ理由から、我々は外部ダイナミックライブラリに値hを求める場合には、Hを見て、即ち、nの値に対応するダイナミックリンクライブラリに見ることができる0x613c30アドレスは、上記の結果が一致する場合です。

3.まとめ

  • 我々はライブラリ関数を呼び出すとき、私たちは、それがコードオプションによって引き起こされるかどうかを検討するために、異常な結果を発見しました。
  • 私たちは、ライブラリを作成する場合は、実装ファイルで条件付きコンパイルを使用してコンパイラオプション構造の部分を入れないようにしてみてください。
  • ライブラリのバージョンをコンパイルしたライブラリ関数とヘッダファイルを呼び出すために使用されるヘッダ・ファイルは、データベースがオフセットアドレスで、その結果、ヘッダファイル構造の変更に結果をアップグレード避けるために保管されています。

おすすめ

転載: www.cnblogs.com/ganchunsheng/p/11781184.html