2016-03-21 5 views
-2

私はすべてのコードを書いたUbuntuで問題なく走った大学のプロジェクトのCコードを書きました。それがマークされたとき、教師はそれが何の生産ももたらさないと言った。しかし、それでも私にはうまくいきますが、教師がWindows上で自分のコードを実行した疑いが正しいことが証明されました。私は問題を捜した。それは以下の通りであった:WindowsとUbuntuで扱われるC配列が異なります

Iは、char配列を有する:

char grade[2]; 

をそれがそれにコピー別のチャーインスタンスの含有配列(char grade_str[3])、、、 "B3" の内容を有している(私は

strcpy(grade, grade_str); 

)、これは間違いである認識しています文字列gradeは(「B3」におそらく今等しい)strcmpを使用して一致を()を取得するために、グレードの完全なファイルに比較です。 gradeこれは、 "B30〜$)"のようなものです。いくつか余分なランダムな文字が付いているので、Windows(正確には7つ)を除いて、一致することはありません。配列は2バイトしかないので、これは許されません。私は問題がほぼ確実に文字列とnullバイトの両方のための十分なスペースを提供していないため、char grade[3];を使用して実際に状況を修正していることを知っています。 しかし、WindowsまたはUbuntuでコンパイルするときにエラーが発生しない理由と、さらにそれがUbuntuで毎回完璧に実行される理由を知りたいですが、Windowsでは決して実行しません。私は今からWindowsとLinux上で自分のコードをチェックしなければならないように感じる...、またはこれらのエラーがコンパイラによって適切に引き上げられていることを確認する手段があるのだろうか?スーパー警戒モード?使用

コンパイラ:

  • のUbuntu:gccのバージョン5.2.1 20151010(Ubuntuの5.2.1-22ubuntu2)
  • のWindows 7:ちょうどそれはですのでかなり確信して、それを更新MINGW32 GCC 4.7
+0

コンパイル時にCなどの言語ですべてのメモリアクセスエラーをキャッチすることは不可能です。 – wRAR

+0

ありがとう、ありがとう。私はそれが可能だと思っていただろう...私は今この質問を削除するので、他の誰かが同じ質問を持っている場合、彼らは再び全面的に尋ねなければならないでしょう。 – Totem

+3

初期化は表示されていません。 'char grade [2];は単なる宣言または暫定的な定義です。 'char [2]'は2つの 'char'sの配列ですが、3つの' chars'をそれに移動しようとします! – Olaf

答えて

3

実際にはLinuxでは正しく動作しないことを理解しておく必要があります...何が起こるかは、ヌル文字が見つかるまでメモリ内の読み取りを続けます。

Linuxでは、あなたの運が良かったと思います。配列の横のバイトはゼロでした.Windowsではあなたは幸運ではありませんでした。

しかし、それはとにかく悪いプログラミングですが、あなたは常に動作していないあなたにそれの例を与えるために...これを見つけるのは非常に困難ですバグにつながることができます他、ヌル文字列を終了

を持っている必要があり、Ubuntuはできますあなたは変数を格納するメモリ内のいくつかの部屋。したがって、配列のような1つまたは2つの変数があります。ある日、別の変数を追加すると、Linuxは配列の後ろにそれを保存します。次に、あなたのプログラムの開始時に動作し、新しい変数を初期化し、配列にアクセスするとクラッシュします。

+0

ありがとう、私はそれが悪いことを認識しています..しかし、それはUbuntuで一貫して動作します。 Windowsの中には何もありません – Totem

+2

いくつかの状況で間違ったプログラムが動作する理由は間違いありませんが、それでも間違いです。 – wRAR

+1

@Totem多分それは "働く" 1000回しかし1001回失敗するでしょう。または、コンパイラを最新バージョンに更新した後は、毎回失敗するかもしれません。それは振る舞い_です。 –

1

実行時にこのようなエラーを検出するには、clangのアドレスサニタイザを使用できます。

みましょうあなたはバグのあるコードを持っていると仮定します。

#include <string.h> 

int main() 
{ 
    char grade[2]; 
    char grade_str[] = "B0"; 

    strcpy(grade, grade_str); 

    return 0; 
} 

あなたは-fsanitize=addressでそれをコンパイルすることができます

clang -fsanitize=address main.c 

あなたがプログラムを実行すると、それはいくつかのデバッグ情報を中断します。

==19588==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd9bcf7422 at pc 0x455bc0 bp 0x7ffd9bcf7350 sp 0x7ffd9bcf6b08 
WRITE of size 3 at 0x7ffd9bcf7422 thread T0 
==19588==WARNING: Trying to symbolize code, but external symbolizer is not initialized! 
    #0 0x455bbf (/tmp/a.out+0x455bbf) 
    #1 0x47afd1 (/tmp/a.out+0x47afd1) 
    #2 0x7fa15d228ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4) 
    #3 0x47ac3c (/tmp/a.out+0x47ac3c) 
[... and so on] 

あなたは、NULLで終了するが、undefined behavior( "UB")ではない文字列に文字列関数を呼び出すclang's documentation

+0

'return strcpy(grade、grade_str) - グレード;'変換問題が発生しました 'intから 'int'への変換は値を変更する可能性があります ' – Michi

+0

@Michi減算を削除しました。 OPエラーを再現する必要はありませんでした。 – user3188346

2

でより多くの情報をご覧いただけます。 UBは、何が起こるかが分からないことを意味します。それはうまくいくかもしれませんし、うまくいかないかもしれません。あなたのケースでは、Linux上で動作しますが、Windowsでは動作しません。いったんUBをお持ちなら、何が起こるかを予測することはできません。

UBは、常にC言語を気にしていることに気づいています。この言語は、あなたがUBをもたらす何かをすることを妨げるものではありません。あなたは自分で慎重にする必要があります。 ClangやGCCのようなコンパイラは、それを検出するのに役立ちますが、保証はありません。

関連する問題