2017-01-24 6 views
0

リターンキャスト(==>)は未定義の動作に配置できますか?コードのアイデアは非常に簡単で、侵入型リスト(plist)を繰り返し、要素が見つかるとその要素を返します。コードは反復するだけなので、リストを変更しないので、constポインタとして渡したいと思います。関数は、オブジェクトを取得し、CONSTとして使用するために使用されるconstキャスト未定義の動作

static my_custom_type_t* get_object_by_id(const my_custom_type_t* plist, const char *my_id) 
{ 
    const my_custom_type_t* obj = NULL; 

    for (obj = plist; obj && strncmp(obj->id, my_id, MAX_SIZE); obj = obj->next) 
    { 
    ; //empty body 
    } 

    ==> return ((my_custom_type_t*) obj); 
} 

:関数はオブジェクトを取得し、非constオブジェクトとしてそれを使用するために使用される

const my_custom_type_t* obj = get_object_by_id(intrusive_list, some_id); 

my_custom_type_t* obj = get_object_by_id(intrusive_list, some_id); 
+1

"const-correctness"とは何かを考えます。もちろん、あなたのコードはそれを壊します!あなたがすべての意味を完全に認識していない場合は、キャストを使用しないでください。 – Olaf

+0

この場合constはリスト構造です。関数はリストを変更していないので壊れていないので、そうではありませんか?私はこのメソッドの外の誰かが後で侵入リストを変更するためにポインタを使うことができますが、関数get_object_by_idは "前/次"ポインタを変更していないことを意味します。 – redobot

+0

なぜあなたは 'const'ポインタも返すだけですか? – Dolda2000

答えて

2

Cは、資格・ポインタへのポインタからの変換を指定しますが、ない他の方法で回避、C11 6.3.2.3/2:任意の修飾子Qの

、非Q-へのポインタ修飾タイプは、 をタイプのq修飾バージョンへのポインターに変換することができます。 元のポインタと変換されたポインタに格納された値は、 と等しくなければなりません。

ただし、CはC11 6.3.2.3/7、以下を可能にする:オブジェクト・タイプに

ポインタは 異なるオブジェクトタイプへのポインタに変換することができます。結果のポインタが参照された型に対して正しく に整列していない場合、動作は未定義です。 それ以外の場合は、再度変換すると、結果は と元のポインタを比較します。平易な英語で

任意ポインタ型は、に他ポインタ型とバックを変換することができます。ポインタ自体にアラインメントの問題がない場合、ポインタが互換性のない型に変換されてから参照が解除されない限り、そのようなコードは問題ありません。修飾されたポインタへの型は、常に互換性のあるポインタ型の型です。

(これはタイプオブジェクトへのポインタを参照することに注意してください - 関数ポインタは特殊なケースである。)

これは本当にそのポインタが最初に指摘している場所によって異なりUBであるか否かだから。あなたは、次の場合はUB、C11 6.7.3/6を起動します。

試みは非const修飾 と左辺値を使用して const修飾型で定義オブジェクトを変更するためになされた場合型は、動作は未定義です。

ポインタがもともと読み取り専用の場所を指していた場合は、未定義の動作が呼び出されます。しかし、constでない、割り当てられた変数を指していれば問題ありません。たとえば、次のコードは問題ありと未定義の動作を呼び出しません。

type t; 
type* p = (type*)(const type*)&t1; 

そうでなければ、誰かがコメントで指摘したように、C標準ライブラリ関数のいくつかは、たとえばstrstrのために、根本的に壊れただろう。

+0

詳細な回答ありがとうございます。この場合、侵入リストは、ヒープ内のユーザーによって割り当てられたオブジェクト(mallocによる動的割り当て)で構成されます。だから私はコードがあなたの説明を考慮に入れて正しいと思う。 – redobot

+0

@redobotその場合、Cは "有効なタイプ"についてのルールを持っています。これは割り当てられたメモリのチャンクがどのタイプのものとして扱われるかを示します。コードが安全であるかどうかを確認するために、呼び出し元コードを確認する必要があります。 – Lundin

+0

発信者コードが大量に終了したため、発信者コードを送信できません。しかし、基本的には、リストからオブジェクトを取得し、変更可能なものとして処理し、呼び出された関数が内部を変更しないようにオブジェクトがconstとして扱われる場所を置きます。 – redobot

0

リターンキャスト(==>)は未定義の動作に配置できますか?

キャストa (my_custom_type_t*)~(const my_custom_type_t*)は、UBを引き起こさない。

どちら行い、以下の原因のいずれかUB

const my_custom_type_t* plist1; 
const my_custom_type_t* obj1 = get_object_by_id(plist1, "x"); 
printf("%d\n", obj1->some_field); 

my_custom_type_t* plist2; 
my_custom_type_t* obj2 = get_object_by_id(plist2, "x"); 
obj2->some_field = 2; 

しかし、次の一つがラッパーであること、2つの機能を記述し、この可能性を避けるために...

const my_custom_type_t* plist3; 
my_custom_type_t* obj3 = get_object_by_id(plist3, "x"); 

// UB 
obj3->some_field = 3; 

をUBを起動しませんもう一方の

static const my_custom_type_t* get_object_by_id_const(
    const my_custom_type_t* plist, const char *my_id) { 
    // as above in OP's post 
    return obj; 
} 

static my_custom_type_t* get_object_by_id_noconst(
    my_custom_type_t* plist, const char *my_id) { 
    const my_custom_type_t* obj = get_object_by_id_const(plist, my_id); 
    return (my_custom_type_t*) obj; 
} 
+0

あなたの答えをありがとう。この場合はconstの逆順で:(const my_custom_type_t *)から(my_custom_type_t *)までは、Lundinの答えで説明されているように問題があります。コメントを読めば、constとno-contの2つの機能を望んでいませんでした。 – redobot

+0

@redobot重要な要件をコメントだけでなく、投稿に編集するのが最適です。この回答のチャックを書いた後、私は「私は2つの機能を作成しないようにしようとしています。 [いつでもあなたが望むものを手に入れることはできない](https://www.youtube.com/watch?v=5BykilS816E)しかし、この答えはコードに必要なものかもしれない。 – chux

+0

@redobot一般的なインタフェースソリューションのために '_Generic'を調べてください。 – chux

関連する問題