web-dev-qa-db-ja.com

C文字列は常にnullで終了しますか、それともプラットフォームに依存しますか?

現在、組み込みシステムを使用して、オペレーティングシステムなしでマイクロプロセッサに文字列を実装する方法を考えています。これまでのところ、私がしていることは、NULLで終了する文字ポインターを持ち、NULLが終了を示す文字列としてそれらを扱うという考えを使用しているだけです。私はこれがかなり一般的であることを知っていますが、あなたが常にこれが当てはまると期待できますか?

私が尋ねる理由は、ある時点でおそらくリアルタイムのオペレーティングシステムを使用することを考えていたからです。現在のコードをできるだけ多く再利用したいと考えています。だから、そこにあるさまざまな選択肢について、文字列が同じように機能することをかなり期待できますか?

私の場合でも、もっと具体的に説明しましょう。シリアルポートを介してコマンドを受け取り、処理するシステムを実装しています。コマンド処理コードを同じにして、RTOS(コマンドを含む))で作成された文字列オブジェクトがすべてNULLで終了することを期待できますか?または、 OS?

更新

ご覧になるようアドバイスを受けた後 この質問 私が求めていることに正確に答えるものではないと判断しました。質問自体は、文字列の長さが常に渡されるべきかどうかを尋ねています。これは、私が求めているものとは完全に異なります。いくつかの回答には有用な情報が含まれていますが、私が探しているものとは異なります。そこでの答えは、なぜか、なぜnotがnull文字で文字列を終了するのかという理由を与えるようです。私が求めているものとの違いは、さまざまなプラットフォームの先天的な文字列が、独自の文字列をnullで終了することを多少なりとも期待できるかどうかです。

13
Snoop

「C文字列」と呼ばれるものは、どのプラットフォームでもnullで終了します。これが標準Cライブラリ関数が文字列の終わりを決定する方法です。

C言語内では、nullで終わらない文字の配列を持つことを妨げるものは何もありません。ただし、文字列の末尾から実行されないようにするには、他の方法を使用する必要があります。

42
Simon B

終了文字の決定は、リテラルのコンパイラと文字列の標準ライブラリの実装一般に委ねられています。これはオペレーティングシステムによって決定されません。

NUL終了の規約は先行標準のCに戻っており、30年以上前に他のことをする環境に出会ったとは言えません。この動作はC89で成文化され、引き続き C言語標準 の一部です(リンクはC99のドラフトへのリンクです):

  • セクション6.4.5は、NULを文字列リテラルに追加することを要求することにより、NULで終了する文字列のステージを設定します。
  • セクション7.1.1は、stringを「最初のnull文字で終了し、最初のnull文字を含む連続した文字のシーケンスとして定義することにより、標準ライブラリの関数にそれをもたらします。 」

誰かが他の文字で終了する文字列を処理する関数を記述できなかった理由はありませんが、目標がプログラマーに適合させることを除いて、ほとんどの場合、確立された標準に反する理由はありません。 :-)

22
Blrfl

私はオペレーティングシステムなしで組み込みシステムで作業しています... NULLで終了する文字ポインターを持ち、NULLが終了を示す文字列としてそれらを扱うという考えを使用しています。これはかなり一般的であることを知っていますが、常にこれが当てはまると期待できますか?

C言語には文字列データ型はありませんが、文字列リテラルはあります。

プログラムに文字列リテラルを配置すると、通常はNULで終了します(ただし、以下のコメントで説明されている特殊なケースを参照してください)。つまり、"foobar"const char *値が期待されます。コンパイラはfoobar⊘をプログラムのconst/codeセグメント/セクションに発行し、式の値はfを格納したアドレスへのポインタになりますキャラクター。 (注:NULバイトを示すためにを使用しています。)

C言語に文字列がある唯一の他の意味は、NULで終了する文字シーケンスを操作する標準ライブラリルーチンがいくつかあることです。これらのライブラリルーチンは、自分で移植しない限り、ベアメタル環境には存在しません。

それらは単にコードです---あなた自身が書いたコードと違いはありません。それらを移植するときにそれらを壊さない場合、それらは常に行うことを実行します(たとえば、NULで停止します)。

3
Solomon Slow

他の人が述べたように、文字列のnull終了はC標準ライブラリの規則です。標準ライブラリを使用しない場合は、任意の方法で文字列を処理できます。

これは、「C」コンパイラを備えたすべてのオペレーティングシステムに当てはまります。また、質問で述べたように、真のオペレーティングシステムで実行されない「C」プログラムを書くこともできます。例としては、私が一度設計したインクジェットプリンターのコントローラーがあります。組み込みシステムでは、オペレーティングシステムのメモリオーバーヘッドは必要ない場合があります。

メモリ不足の状況では、たとえば、プロセッサの命令セットと比較して、コンパイラの特性を調べます。文字列が頻繁に処理されるアプリケーションでは、文字列長などの記述子を使用することが望ましい場合があります。 CPUが短いオフセットやアドレスレジスタを使用した相対オフセットを処理するのに特に効率的なケースを考えています。

それでは、アプリケーションでより重要なのは、コードサイズと効率、またはOSやライブラリとの互換性です。別の考慮事項は、保守性かもしれません。慣習から離れれば離れるほど、他の誰かが維持するのが難しくなります。

2
Hugh Buntu

他の人たちは、Cでは文字列が主にあなたが作成した文字列であるという問題に対処しています。しかし、あなたの質問にはいくつかの混乱があるようです。ターミネーター自体、そしてある観点からは、これはあなたの立場にいる誰かが心配していることかもしれません。

C文字列はnullで終了します。つまり、ヌル文字NULで終了します。ヌルポインターNULLで終了することはありません。これは、完全に異なる種類の値であり、完全に異なる目的を持っています。

NULの整数値はゼロであることが保証されています。文字列内では、基になる文字タイプのサイズも持ち、通常は1になります。

NULLが整数型であることは保証されていません。 NULLはポインターコンテキストで使用することを目的としており、通常、ポインター型を持つことが期待されています。コンパイラーが優れている場合、これは文字または整数に変換されません。 NULLの定義にはグリフ0が含まれますが、実際にその値[1]があることは保証されていません。また、コンパイラが定数を1文字#defineNULLreallyは非ポインターコンテキストでは意味がないため)多くの場合、そうではありません)したがって、拡張コードは実際にはゼロ値を含むことが保証されていません(たとえそれが紛らわしいことにゼログリフが含まれます)。

NULLを入力すると、サイズが1(または別の文字サイズ)になる可能性も低くなります。これにより、追加の問題が発生する可能性があります。ただし、実際の文字定数にはほとんどの場合文字サイズがありません。

これで、ほとんどの人はこれを見て「すべてゼロのビット以外のヌルポインター?なんてナンセンスだ」と考えるでしょう。しかし、そのような仮定はx86のような一般的なプラットフォームでのみ安全です。他のプラットフォームをターゲットにすることへの関心について明示的に述べたので、コードをポインターと整数の間の関係の性質に関する仮定から明示的に分離しているので、この問題を考慮する必要があります。

したがって、C文字列はnullで終了しますが、NULLではなくNUL(通常は'\0')で終了します。文字列ターミネータとしてNULLを明示的に使用するコードは、単純なアドレス構造のプラットフォームで機能し、多くのコンパイラでコンパイルすることもできますが、Cは完全に正しくありません。


[1]実際のnullポインター値は、ポインター型に変換されるコンテキストで0tokenを読み取るときにコンパイラーによって挿入されます。これは整数value 0からの変換ではなく、変数の動的な値など、トークン0自体以外が使用された場合の保持は保証されません。変換も元に戻すことはできません。また、整数に変換するときにnullポインターが値0を生成する必要はありません。

1
Leushenko

私はCで文字列を使用しています。つまり、nullで終わる文字を文字列と呼びます。

ベアメタルまたはWindows、Linuxなどのオペレーティングシステムで使用する場合、問題はありませんRTOS:(FreeRTO、OSE)。

組み込みの世界では、ヌル終了は実際には文字を文字列としてトークン化するのに役立ちます。

多くの安全上重要なシステムでCの文字列を使用しています。

不思議に思うかもしれませんが、Cの実際の文字列は何ですか?

Cスタイルの文字列は配列であり、「this」などの文字列リテラルもあります。実際には、これらの文字列タイプはどちらも、メモリ内で隣り合って並んでいる単なる文字の集まりにすぎません。

二重引用符で囲まれた文字列を記述すると、Cは自動的に\ 0文字で終了する文字列を含む文字の配列を作成します。

たとえば、文字の配列を宣言して定義し、文字列定数で初期化できます。

char string[] = "Hello cruel world!";

簡単な答え:null終了の文字の使用について心配する必要はありません。これは、プラットフォームに関係なく機能します。

1
danglingpointer

他の人が言ったように、ヌル終了は標準Cではほとんど普遍的です。しかし(他の人も指摘したように)100%ではありません。 (別の)例では、VMSオペレーティングシステムは通常、「文字列記述子」と呼ばれるものを使用しました http://h41379.www4.hpe.com/commercial/c/docs/5492p012.html Cでアクセスby#include <descrip.h>

アプリケーションレベルのものは、null終端を使用することもしないこともできますが、開発者は適切だと考えています。ただし、低レベルのVMSのものには、null終了をまったく使用しない記述子が絶対に必要です(詳細については、上記のリンクを参照してください)。これは主に、VMS内部を直接使用するすべての言語(C、アセンブリなど)がそれらと共通のインターフェースを持つことができるようにするためです。

したがって、同様の状況を予想している場合は、「ユニバーサルnull終了」が必要であると示唆するよりも、いくらか注意する必要があります。私があなたがしていることをしているならもっと注意するでしょうが、私のアプリケーションレベルのものについては、ヌル終了と仮定するのが安全です。私はあなたに同じレベルの安全性を提案するつもりはありません。コードは、将来の時点でアセンブリや他の言語コードとインターフェイスする必要がある場合があります。これは、ヌル終了文字列のC標準に常に準拠するとは限りません。

1
John Forkosh

組み込みの安全性が重要なリアルタイムシステムの私の経験では、CとPascalの両方の文字列規則を使用すること、つまり、文字列の長さを最初の文字として指定し(長さを255に制限する)、少なくとも1つの0x00を含む文字列(NUL)。これにより、使用可能なサイズが254に減少します。

これの1つの理由は、最初のバイトが受信された後に予想されるデータの量を知ることです。もう1つは、そのようなシステムでは、可能な場合は動的バッファーサイズが回避されることです-固定256バッファーサイズの割り当てがより高速で安全です(いいえmallocが失敗したかどうかを確認する必要があります)。もう1つは、通信している他のシステムがANSI-Cで記述されていない可能性があることです。

組み込み作業では、文字列形式、エンディアン、整数サイズなどを含むすべての通信構造を定義するインターフェイスコントロールドキュメント(IDC)をできるだけ早く確立して維持することが重要です(理想的には開始する前に)、そしてそれはあなたとすべてのチームでなければなりません、システムを書くときは神聖な本です-誰かが新しい構造を導入したりフォーマットしたい場合必須そこに文書化最初影響を受ける可能性のあるすべての人に通知(変更を拒否するオプションを使用可能)

0
Steve Barnes