私が試してみました;
void *malloc(unsigned int);
struct deneme {
const int a = 15;
const int b = 16;
};
int main(int argc, const char *argv[])
{
struct deneme *mydeneme = malloc(sizeof(struct deneme));
return 0;
}
そして、これはコンパイラのエラーです:
gereksiz.c:3:17: error: expected ':', ',', ';', '}' or '__attribute__' before '=' token
そして、これも。
void *malloc(unsigned int);
struct deneme {
const int a;
const int b;
};
int main(int argc, const char *argv[])
{
struct deneme *mydeneme = malloc(sizeof(struct deneme));
mydeneme->a = 15;
mydeneme->b = 20;
return 0;
}
そして、これはコンパイラのエラーです:
gereksiz.c:10:5: error: assignment of read-only member 'a'
gereksiz.c:11:5: error: assignment of read-only member 'b'
そしてどちらもコンパイルされませんでした。 mallocでメモリを割り当てるときに、構造体内のconst変数を初期化する方法はありますか?
Mallocされた構造体のフィールドを初期化するには、constをキャストする必要があります。
struct deneme *mydeneme = malloc(sizeof(struct deneme));
*(int *)&mydeneme->a = 15;
*(int *)&mydeneme->b = 20;
あるいは、構造体の初期化されたバージョンを作成し、それをmemcpyすることができます。
struct deneme deneme_init = { 15, 20 };
struct deneme *mydeneme = malloc(sizeof(struct deneme));
memcpy(mydeneme, &deneme_init, sizeof(struct deneme));
これを頻繁に実行する場合は、deneme_initを静的またはグローバル、あるいはその両方にすることができます(したがって、一度構築するだけで済みます)。
C11標準参照を使用して、コメントの一部で提案されているように、このコードが未定義の動作ではない理由の説明:
malloc
によって返されるスペースは「const修飾型のオブジェクトdefined」ではないため、このコードは6.7.3/6に違反していません。式mydeneme->a
はオブジェクトではなく、式です。 const
- qualified型ですが、const修飾型で定義されていない(実際には、どの型でも定義されていない)オブジェクトを示します。
有効なタイプ(6.5/6)は書き込みごとに更新されるため、malloc
によって割り当てられたスペースに書き込むことにより、厳密なエイリアスのルールに違反することはありません。
(ただし、malloc
によって割り当てられたスペースから読み取ると、厳密なエイリアシングルールに違反する可能性があります)。
Chrisのコードサンプルでは、最初のコードは整数値の有効な型をint
に設定し、2番目のコードは有効な型をconst int
に設定しますが、どちらの場合も*mydeneme
を通じてこれらの値を読み取ります厳密なエイリアシングルール(6.5/7箇条書き2)では、オブジェクトの有効なタイプと同等またはそれ以上に修飾された式を介してオブジェクトを読み取ることが許可されているため、正しいです。式mydeneme->a
はタイプconst int
を持っているので、有効なタイプint
およびconst int
のオブジェクトを読み取るために使用できます。
このようにしようとしましたか:
int main(int argc, const char *argv[])
{
struct deneme mydeneme = { 15, 20 };
struct deneme *pmydeneme = malloc(sizeof(struct deneme));
memcpy(pmydeneme, &mydeneme , sizeof(mydeneme));
return 0;
}
私はテストしていませんが、コードは正しいようです
他の人が言ったように、彼の解決策は標準に従ってUndefined Behaviourを与えると思うので、私はChrist Doddの答えに同意しません。
未定義の動作を呼び出さない方法でconst
修飾子を「回避」するには、次の解決策を提案します。
malloc()
呼び出しで初期化されたvoid*
変数を定義します。struct deneme
)を定義して初期化し、const
修飾子が文句を言わないように(つまり、宣言行自体で)初期化します。memcpy()
を使用して、struct deneme
オブジェクトのビットをvoid*
オブジェクトにコピーします。struct deneme
オブジェクトへのポインタを宣言し、以前に(void*)
にキャストした(struct deneme *)
変数に初期化します。したがって、私のコードは次のようになります:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct deneme {
const int a;
const int b;
};
struct deneme* deneme_init(struct deneme data) {
void *x = malloc(sizeof(struct deneme));
memcpy(x, &data, sizeof(struct deneme));
return (struct deneme*) x;
}
int main(void) {
struct deneme *obj = deneme_init((struct deneme) { 15, 20, } );
printf("obj->a: %d, obj->b: %d.\n", obj->a, obj->b);
return 0;
}
興味深いことに、このC99の方法はclangでは機能しますが、gccでは機能しません。
int main(int argc, const char *argv[])
{
struct deneme *pmydeneme = malloc(sizeof(struct deneme));
*pmydeneme = (struct deneme) {15, 20};
return 0;
}