2017-09-08 7 views
0

Nullターミネーターが埋め込まれている場合は、そのUBの後にある値にアクセスするための明確な定義がされていますか?レコードの埋め込みヌルターミネータUBの後に文字列の一部にアクセスしていますか?

#include <stdio.h> 

const char foo[] = "abc\0def"; 
int main() { 
    printf("%s", foo+4); 
    return sizeof(foo); 
} 

、それはあなたが期待するかもしれないものを出力します。

def 
+3

いいえ、メモリが割り当てられ、UBが存在しません。 – user0042

+1

これは、 'sizeof'が文字列の長さではなく配列のサイズを返すという点を除いては問題ありません。 –

答えて

3

は、埋め込まれたnullは未定義の動作ではありません。文字列がヌル文字で終了すると予想される関数を使用すると、となります。しかし、コンテンツにかかわらず、正常に割り当てられた配列の全幅にアクセスすることに関して、間違ったり悪いことは何もありません。あなたは文字列が重要になることがあり保存方法あなたはstd::stringにこのデータを保存しようとすると、(あなたはすべての文字列、TBHを処理する方法である)、:しかし観察する

一つ。

std::string str1 = foo; //contents of str1 becomes "abc". 
std::string str2 = std::string(foo, sizeof(foo)); //contents of str2 becomes "abc\0def" 
2

[dcl.init.string]状態は

狭い文字型(3.9.1)のアレイ、アレイchar16_t、char32_tアレイ、またはwchar_tの配列リテラル狭い文字列で初期化することができ、char16_t文字列リテラル、char32_t文字列リテラル、またはワイド文字リテラル、または中括弧(2.14.5)で囲まれた適切に型付けされた文字列リテラルを使用します。 文字列リテラルの値の連続する文字は、配列の要素を初期化します。

強調鉱山

だから埋め込まれたヌルではない問題は、それだけで配列の要素となります。配列はコンテナのサイズになっているので、埋め込まれたnullの後に要素があり、それらにアクセスすることは安全であることがわかっているすべての文字とエスケープシーケンスが格納されています。

実際に埋め込まれたnullの唯一の問題は、すべてのC関数がnullにヒットしたときに停止し、文字列を完全に処理しないことです。代わりにstd::stringを使用することを検討しても問題はありません。

2

C文字列にアクセスすると、ヌル終了文字自体がになります。は未定義の動作です。しかし、我々はのように未定義の振る舞いをもたらしますが、まったく別の理由があります:

文字列のために予約されたchar配列の最後の位置に終端ヌル文字が存在する場合、終わりを越えて文字列にアクセスすると、その境界から外れます。そして、この範囲外のアクセスが...本当に未定義の動作を生成するものです

編集:

[余談:?であることUB]

UB、未定義の動作、意味のある行動がないので、定義できない動作です。未定義の動作に依存すると、期待される結果を得ることを含む何らかの結果が生じることがあるが、他の時間(例えば、コンパイラのバージョンを切り替えた後、単に再コンパイルした後、ただ1つの同じプログラムを再起動した後であっても)。したがって、未定義の動作に依存するプログラムは、明確に定義されていないとみなされます。

例:すでに削除されているオブジェクト(「ダングリングポインター」)を指すポインターを間接的に参照するか、疑問点に近づいています。範囲外の配列にアクセスします。 (悪い!!!)は、与えられたアドレスにあるまったく異なるオブジェクトのメモリを上書きします(プログラムが実行されるたびに同じオブジェクトである必要はありません1つのプログラム実行でも実行されません)。

未定義の動作は、それコンパイラのベンダーに委ねられ、一定の合理的な制限内で動作を定義します。

例:負の整数の右シフト - 符号拡張の有無にかかわらず発生する可能性があります(したがって、算術演算または論理シフトが可能です)。どちらが当てはまるかは標準では規定されていませんが、負の整数で右シフトを使用することはよく定義されています。

+0

脇に:妥当な最適化のように最初のヌルターミネーターの後にすべてを落とすように思えるので、私は尋ねました - 指定できるように、しかし私はそれがあるかどうかは分かりませんでした。 [もちろん、私はgodboltでコンパイルを試みて、実際に何が起こったかを指摘した] – wrhall

+0

"最初のヌルターミネーターの後にドロップする" - 100%ではない - 配列はそこにあり、固定サイズであり、その一部あなたが "別の目的のために再利用"を意味するならば、あなたはそれを自由にすることができます - ただあなたが配列の範囲を超えないようにしてください... – Aconcagua

+0

申し訳ありません - 合理的*コンパイラ*ヌルターミネータの後ろのすべてを落とすために...つまり、ヌルターミネータを超えて配列を割り当てない。 – wrhall

関連する問題