web-dev-qa-db-ja.com

ASCII文字列とエンディアン

私と一緒に働くインターンは、彼がエンディアンの問題についてコンピューターサイエンスで受けた試験を見せてくれました。 ASCII文字列「My-Pizza」を示す質問があり、学生はその文字列がリトルエンディアンコンピュータのメモリでどのように表現されるかを示さなければなりませんでした。もちろん、これは次のように聞こえますASCII文字列はエンディアンの問題の影響を受けないため、トリックの質問です。

しかし、驚いたことに、彼の教授は、弦は次のように表されると主張していると主張している。

P-yM azzi

私はこれが正しくないことを知っています。 ASCII文字列がどのマシンでもそのように表現される方法はありません。しかし、どうやら教授はこれを主張しています。それで、私は小さなCプログラムを書き、インターンにそれを彼の教授に。

#include <string.h>
#include <stdio.h>

int main()
{
    const char* s = "My-Pizza";
    size_t length = strlen(s);
    for (const char* it = s; it < s + length; ++it) {
        printf("%p : %c\n", it, *it);
    }
}

これは、文字列が「My-Pizza」としてメモリに保存されていることを明確に示しています。 1日後、インターンは私に戻り、教授がCが自動的にアドレスを自動的に変換して文字列を適切な順序で表示していると主張していることを教えてくれました。

私は彼の教授は正気でないと彼に言った、そしてこれは明らかに間違っている。しかし、ここで自分の正気を確認するためだけに、私がこれをstackoverflowに投稿して、他の人に自分の言っていることを確認してもらうことにしました。

だから、私は尋ねます:ここに誰がいますか?

40
Charles Salvia

間違いなく、あなたは正しいです。

ANSI C標準6.1.4は、文字列リテラルがリテラル内の文字を「連結」することによってメモリに格納されることを指定しています。

ANSI規格6.3.6では、ポインタ値に対する加算の影響も規定されています。

整数型の式がポインターに加算またはポインターから減算されると、結果はポインターオペランドの型になります。ポインターオペランドが配列オブジェクトの要素を指し、配列が十分に大きい場合、結果は元の要素からの要素オフセットを指し、結果の配列要素と元の配列要素の添え字の差が積分式と等しくなるようにします。

この人物に起因するアイデアが正しかった場合、整数が配列インデックスとして使用されている場合、コンパイラーは整数演算を行う必要があります。想像力に任されている他の多くの誤りも発生します。

(文字列初期化子とは異なり)、 'ABCD'などのマルチバイト文字定数areがエンディアン順に格納されているため、混乱する可能性があります。

人がこれについて混乱するかもしれない多くの理由があります。他の人がここで示唆しているように、彼は、int値を読みやすくするために内容がバイトスワップされているデバッガーウィンドウに表示されるものを誤って読んでいる可能性があります。

28
Heath Hunnicutt

教授は混乱しています。 「P-yM azzi」のようなものを表示するには、メモリを「4バイト整数」モードで表示し、同時に各整数の「文字解釈」を高次で表示するメモリ検査ツールを使用する必要があります。バイトから下位バイトモード。

もちろん、これは文字列自体とは関係ありません。そして、文字列自体がリトルエンディアンのマシンでそのように表現されていると言うことはまったくナンセンスです。

16
AnT

文字あたり8ビットを使用するシステムについて話している場合、教授は間違っています。

私は、実際には16ビット文字を使用する組み込みシステムで作業することが多く、各Wordはリトルエンディアンです。このようなシステムでは、文字列「My-Pizza」は「yMP-ziaz」として実際に格納されます。

ただし、文字ごとに8ビットのシステムである限り、文字列は、上位アーキテクチャのエンディアンに関係なく、常に「My-Pizza」として保存されます。

10
Dmitry Brant

エンディアンは、マルチバイト値内のバイトの順序を定義します。文字列はシングルバイト値の配列です。したがって、各値(文字列内の文字)はリトルエンディアンとビッグエンディアンの両方のアーキテクチャで同じであり、エンディアンは構造体の値の順序に影響しません。

9
Priyanshu Jain

しかし、驚いたことに、彼の教授は、弦は次のように表されると主張していると主張している。

P-yM azzi

それは何として表されますか? 32ビット整数ダンプとしてユーザーに表されますか?またはコンピュータのメモリにP-yM azziとして表示/レイアウトしますか?

コンピュータがリトルエンディアンアーキテクチャであるため、「My-Pizza」が「P-yM azzi」としてコンピュータのメモリに表示/レイアウトされると教授が言った場合、誰かがその教授に教えてもらうデバッガー!教授の混乱の原因はそこにあると思います。教授はコーダーではない(私は教授を見下しているわけではありません)ので、彼には方法がないと思います彼がエンディアンネスについて学んだことをコードで証明してください。

たぶん、教授は約1週間前にエンディアンらしさを学び、それからデバッガを誤って使用し、コンピュータに関する彼の新しくユニークな洞察についてすぐに喜んで、それをすぐに生徒に伝えました。

機械のエンディアン性がアスキー文字列がメモリ内でどのように表現されるかに関係があると教授が言った場合、彼は彼の行動を整理する必要があり、誰かが彼を修正する必要があります。

代わりに、マシンのエンディアンに応じて整数がマシンでどのように表現/レイアウトされるかについて教授が例を挙げた場合、彼の生徒は彼がすべてについて何を教えているかを理解することができます。

2
Michael Buen

あなたは興味があるかもしれません、ビッグエンディアンのマシンでリトルエンディアンのアーキテクチャをエミュレートすること、またはその逆も可能です。コンパイラーは、char*ポインターの最下位ビットを逆参照するたびに自動的に混乱させるコードを発行する必要があります。32ビットマシンでは、00 <-> 11と01 <-> 10をマップします。

したがって、ビッグエンディアンマシンで0x01020304の数値を書き込んで、その最初のバイトをこのアドレス変更で読み取ると、最下位バイトの0x04が返されます。ハードウェアはビッグエンディアンですが、C実装はリトルエンディアンです。

短いアクセスにも同様のトリックが必要です。アライメントされていないアクセス(サポートされている場合)は、隣接するバイトを参照しない場合があります。また、Wordより大きい型のネイティブストアを使用することもできません。一度に1バイトずつ読み戻すと、Wordスワップされたように見えるからです。

ただし、明らかにリトルエンディアンマシンは常にこれを行うわけではありません。これはveryスペシャリストの要件であり、ネイティブABIを使用できなくなります。教授は実際の数値を「実際には」ビッグエンディアンであると考えているように聞こえ、リトルエンディアンアーキテクチャが実際に何であるか、および/またはそのメモリがどのように表現されているかを深く混乱しています。

文字列が32ビットファイルのマシンで「次のように表現される」P-yM azziであることは事実ですが、「次のように表現する」とは、「表現の単語をアドレスの昇順で読み取るが、各単語のバイトを大きく表示する」 -エンディアン」。他の人が言ったように、これは一部のデバッガーのメモリビューで実行できることなので、実際にはaメモリの内容の表現です。ただし、個々のバイトを表す場合は、各ワードを複数文字リテラルとして表すのではなく、ワードがb-eとl-eのどちらで保存されているかに関係なく、アドレスの昇順でリストするのが一般的です。確かに、ポインタをいじるようなことは行われておらず、教授の選択した表現が彼に何かがあると考えるように導いた場合、それは彼を誤解させた。

1
Steve Jessop

私は教授がエンディアン/ NUXI問題について類推してポイントを作ろうとしていたと思いますが、それを実際の文字列に適用するとあなたは正しいです。彼が学生にポイントを教えようとしていて、問題を特定の方法でどのように考えようとしていたかという事実から脱線しないでください。

1
Dinah

私はこれに遭遇し、それを片付ける必要性を感じました。 bytesとWordsの概念、または address の方法に対処した人はいません。 byte は8ビットです。 Word はバイトのコレクションです。

コンピュータが次の場合:

  • バイトアドレス可能
  • 4バイト(32ビット)ワード
  • 単語揃え
  • メモリは「物理的に」表示されます(ダンプおよびバイトスワップされません)

それから、確かに、教授は正しいでしょう。彼がこれを示さなかったことは、彼が話していることを正確に知らないことを証明しますが、彼は基本的な概念を理解しました。

ワード内のバイト順:(a)ビッグエンディアン、(b)リトルエンディアン

Byte Order Within Words: (a) Big Endian, (b) Little Endian

ワード内の文字および整数データ:(a)ビッグエンディアン、(b)リトルエンディアン

Character and Integer Data in Words: (a) Big Endian, (b) Little Endian

参照

0
nickaknudson

AFAIK、エンディアンは、大きな値を小さな値に分割したい場合にのみ意味があります。したがって、Cスタイルの文字列は影響を受けないと思います。結局のところ、文字の配列だけだからです。 1バイトだけを読み取っている場合、左または右から読み取るとどうなりますか?

0
akif

また、(これを長い間使っていなかったので、私は間違っているかもしれません)文字列は「パックされた配列」として表されるパスコールを考えているかもしれません。IIRCは4バイト整数にパックされた文字ですか?

0
Brian Postow

教授の頭を読むのは難しく、コンパイラはBEシステムとLEシステムの両方で隣接する増加するアドレスにバイトを格納する以外に何もしていませんが、メモリをワードサイズの数値で表示するのはis Wordのサイズに関係なく、1,000は1,000と書きます。 000,1ではありません。

$ cat > /tmp/pizza
My-Pizza^D
$ od -X /tmp/pizza
0000000 502d794d 617a7a69
0000010
$ 

レコードの場合、y == 79、M == 4d。

0
DigitalRoss