2016-12-26 2 views
-3

-Theory Cのメモリに異なる種類の読み取り:書き込み及び

Iは、異なるタイプの変数Sのセットがあると私は今Sの大きさのメモリアドレスへのポインタPの指示を有する、I Sのすべての値をPに代入してからそれらを読み取る必要があります。

これの背後にある点は、手動で構造体に似たものを手動で構築することです。

私がやった - 何:

は我々がここでの問題は、私は私の割り当てだということです

uint8_t* foo(int i, char c, char* s) { 
    uint8_t* r = malloc(sizeof(i) + sizeof(c) + sizeof(s)); 
    *r = i; 
    *(r+sizeof(i)) = c; 
    *(r+sizeof(i)+sizeof(c)) = s; 
    return r; 
} 

int main(void) { 
    uint8_t * a = foo(500, 'a', "hello"); 
    printf("%d, %c, %s\n", *a, *(a+sizeof(int)), (a+sizeof(int)+sizeof(char))); 
    return 0; 
} 

私たちのS iとして、char型のC、およびするchar * sのint型持っていると言うことができますデータを第1のバイトのみに変換し、第1のバイトのみを読み出す。

-The質問:

は、どのように私がfooの* R = Iにコンパイラに伝えることができます。 iを* rの次の4バイトに割り当て、次にメインの読み込み* aを4バイトとして割り当て、次にcとsについて同じことをしますか?

+0

'sizeof(s)'は関数に渡される文字列データについて関数に何も伝えていないことを祈っています。これはポインタのサイズです。 –

+0

はい、私は、ポインタを含む任意の型を格納しても構いません – Naheel

+0

'*(r + sizeof(i)+ sizeof(c))= s;'は文字列をコピーせず、文字列ポインタ'uint8_t'にあります。 –

答えて

1

あなたは、あなたの左辺値をキャストする必要があり、彼らは右のタイプを持つように:

int main(void) { 
    uint8_t *a = foo(500, 'a', "hello"); 
    printf("%d, %c, %s\n", *(int *)a, *(char *)(a + sizeof(int)), *(char **)(a + sizeof(int) + sizeof(char))); 
    return 0; 
} 

それらを読むためには
uint8_t *foo(int i, char c, char *s) { 
    uint8_t *r = malloc(sizeof i + sizeof c + sizeof s); 
    *(int *)r = i; 
    *(char *)(r + sizeof i) = c; 
    *(char **)(r + sizeof i + sizeof c) = s; 
    return r; 
} 

が、適切な型にキャストすることも必要です@chuxはコメントで指摘しているとおり、これは実際には未定義の動作です。もちろん@デビッドカレンの答えは、エンジニアリングの観点から最適なソリューション残るものの

// Get the smallest multiple of _Alignof(type) >= off 
#define GET_ALIGNED_OFFSET(off, type) ((off + _Alignof(type) - 1)/_Alignof(type) * _Alignof(type)) 

uint8_t *foo(int i, char c, char *s) { 
    size_t offset1 = GET_ALIGNED_OFFSET(sizeof i, char); 
    size_t offset2 = GET_ALIGNED_OFFSET(offset1 + sizeof c, char *); 
    uint8_t *r = malloc(offset2 + sizeof s); 
    *(int *)r = i; 
    *(char *)(r + offset1) = c; 
    *(char **)(r + offset2) = s; 
    return r; 
} 

:以前と同じ精神で、標準に準拠したコードを取得するために、C11 _Alignof演算子を使用することが可能です。

+0

'*(char **)(r + sizeof i + sizeof c) = s; 'は栄養所要量によって失敗する可能性があります。 – chux

+0

@chux:はい、ありがとう! ;)私は自分の答えを更新しました。 – md5

+0

@chux:BTW 2番目のステートメント '*(char *)(r + sizeof i)'も未定義の振る舞いです。標準では 'char'の整列要件が1であるとは言いません(ちょうど"弱い ")。 – md5

2

私はコンピューターを可能な限り数学的にするのが好きです。このような状況では、私が使用しstruct

500, a, hello 

#include <stdio.h> 
#include <stdlib.h> 

struct multi_type { 
    int i; 
    char c; 
    char *s; 
}; 

struct multi_type *foo(int i, char c, char *s) { 
    struct multi_type *result = malloc(sizeof(*result)); 
    if (result == NULL) { 
     return NULL; 
    } 
    result->i = i; 
    result->c = c; 
    result->s = s; 
    return result; 
} 

int main(void) { 
    struct multi_type *a = foo(500, 'a', "hello"); 
    if (a) { 
     printf("%d, %c, %s\n", a->i, a->c, a->s); 
     free(a); 
    } 
    return 0; 
} 

出力このコードは、保守が容易です。 struct multi_typeのタイプのいずれかが変更された場合、またはタイプを追加する必要がある場合は、変更するコードが少なくなります。

+0

実際には、私の質問の背後にある点は、構造体と同様のことをすることですが、より高い自由と数学を自分自身で行うことです。 – Naheel

+0

質問のタイトルまたは本文から、自分で数学を行いたいことは明らかです。質問のタイトルと本文をより明確に更新することを検討する必要があります。しかし、私の答えは、手動で数学をしたくない人にとって役に立ちます。 –

+0

この答えは、 '*(char **)(r + sizeof i + sizeof c)= s;'の未定義の振る舞いとは異なり、移植性と正確性があります。 – chux