prosource

C에서 구조물의 const를 초기화하는 방법(malloc 포함)

probook 2023. 10. 20. 13:50
반응형

C에서 구조물의 const를 초기화하는 방법(malloc 포함)

노력했습니다.

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 표준 참조를 사용하여 이 코드가 일부 주석에서 제안한 바와 같이 정의되지 않은 동작이 아닌 이유를 설명합니다.

  • 이 코드는 공간이 반환되므로 6.7.3/6을 위반하지 않습니다.malloc는 "정규 형식으로 정의된 개체"가 아닙니다.표정이mydeneme->a개체가 아니라 표현입니다.있기는 하지만const-qualified type, const-qualified type으로 정의되지 않은 객체를 의미합니다(실제로는 어떤 형식으로도 정의되지 않았습니다).

  • 에 의해 할당된 공간에 쓰기로 인해 엄격한 앨리어싱 규칙이 위반되지 않습니다.malloc, 유효 유형(6.5/6)이 각 쓰기별로 업데이트되기 때문입니다.

(엄격한 앨리어싱 규칙은 에 의해 할당된 공간에서 읽음으로써 위반될 수 있습니다.malloc단).

Chris의 코드 샘플에서 첫번째 것은 정수 값의 유효 유형을 다음과 같이 설정합니다.int, 그리고 두번째는 유효 타입을 다음과 같이 설정합니다.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;
}

테스트는 안했지만 코드는 맞는 것 같습니다.

흥미로운 점은 이 C99 방식이 클랑에서는 작동하지만 gcc에서는 작동하지 않는다는 것을 발견했습니다.

int main(int argc, const char *argv[])
{
    struct deneme *pmydeneme = malloc(sizeof(struct deneme));
    *pmydeneme = (struct deneme) {15, 20};
    return 0;
}

@Chris Dodd의 답변에 대해 자세히 설명하자면, 표준의 "언어-변호사" 세부사항을 읽어보니 이 코드가 잘 정의되어 있는 것 같습니다.

struct deneme deneme_init = { 15, 20 };
struct deneme *mydeneme = malloc(sizeof(struct deneme));
memcpy(mydeneme, &deneme_init, sizeof(struct deneme));

또는 일정한 조건을 갖춘 완전한 구조 객체를 동적으로 생성하려면 다음과 같이 하십시오.

const struct deneme deneme_init = { 15, 20 };
struct deneme *mydeneme = malloc(sizeof(struct deneme));
memcpy(mydeneme, &deneme_init, sizeof(struct deneme));

const struct deneme *read_only = mydeneme; 

근거:

이 문제의 진상을 규명할 때 가장 먼저 확립해야 할 것은 소위 l값에 형식이 있는 경우와 그런 경우에 형식에는 수식어가 붙는가 아닌가 하는 것입니다.이는 C116.3.2.1/1에 정의되어 있습니다.

lvalue는 개체를 지정할 가능성이 있는 식(공백이 아닌 개체 유형)으로, 평가할 때 개체를 지정하지 않으면 동작이 정의되지 않습니다.개체가 특정 유형을 가지고 있다고 할 때 유형은 개체를 지정하는 데 사용되는 l 값으로 지정됩니다.수정 가능한 l 은 배열 유형이 없고, 불완전한 유형이 없으며, 정규화된 유형이 없으며, 구조 또는 유니언인 경우 정규화된 유형이 있는 멤버(모든 포함된 Aggregate 또는 유니언의 멤버 또는 요소 포함)가 없습니다.

따라서 분명한 것은 alvalue에는 형식만 있는 것이 아니라 한정자도 있다는 것입니다.수정 가능한 l 값이 아닌 경우, 또는 수정 가능한 l 값이 아닌 경우, 또는 수정 가능한 멤버가 있는 구조물입니다.

"엄격한 앨리어싱"과 유효 유형의 규칙으로 넘어가면 C11 6.5/7:

저장된 값에 액세스할 수 있는 개체의 유효한 유형은 선언된 개체 유형(있는 경우)입니다.87)문자 유형이 아닌 유형의 l 값을 통해 선언된 유형이 없는 개체에 값이 저장된 경우, l 값의 유형은 해당 액세스 및 저장된 값을 수정하지 않는 후속 액세스에 대한 개체의 유효 유형이 됩니다.값이 선언된 유형이 없는 개체로 복사된 경우 다음을 사용합니다.memcpy아니면memmove 해당 및됩니다)입니다. 그러면 해당 액세스 및 값을 수정하지 않는 후속 액세스에 대해 수정된 개체의 유효 유형은 값이 복사되는 개체의 유효 유형입니다.선언된 유형이 없는 개체에 대한 다른 모든 액세스의 경우 개체의 유효 유형은 액세스에 사용되는 l 값의 유형입니다.

  1. 할당된 개체에 선언된 형식이 없습니다.

이는 malloc에 의해 반환된 할당된 청크가 할당 또는 할당을 통해 alvalue write 액세스를 통해 해당 메모리 위치에 무언가가 저장될 때까지 유효한 유형이 없음을 의미합니다.memcpyl을 가져옵니다 그런 다음 해당 쓰기 액세스에 사용되는 l 값의 유효한 유형을 가져옵니다.

특히 해당 메모리 위치를 가리키는 포인터의 유형은 전혀 무관합니다..volatile bananas_t*l 값에 액세스하는 데 사용되지 않기 때문입니다(적어도 아직은 아님).lvalue access에 사용되는 유형만 중요합니다.

여기서 퍼지가 발생합니다. 이 쓰기 액세스가 수정 가능한 l 값을 통해 수행되는지 여부가 중요할 수 있습니다.위의 유효한 유형의 규칙은 한정자와 "엄격한 별칭 지정 규칙"에 대해 언급하지 않습니다. 개체가 "정격한 유형"으로 별칭 지정될 수도 있고, 그 반대일 수도 있습니다.

그러나 유효 유형이 읽기 전용인지 아닌지가 중요할 수 있는 다른 경우가 있는데, 가장 주목할 것은 유효 유형이 정수가 아닌 개체에 대해 나중에 정수가 아닌 l값 액세스를 시도하는 경우입니다. (C116.7.3/6 "정수가 아닌 l값을 사용하여 정수가 있는 개체를 수정하려고 시도하는 경우ified type, 동작은 정의되지 않습니다.") 이전에 인용된 l값 이상의 부분에서 표준이 명시적으로 언급하지 않더라도 유효 type에 한정자가 있는 것이 타당합니다.

따라서 절대적으로 확실하게 하기 위해서는 lvalue access에 사용되는 타입을 구해야 합니다.전체 개체가 읽기 전용인 경우 이 게시물 위에 있는 두 번째 토막글을 사용해야 합니다.그렇지 않으면 읽기/쓰기(자격을 갖춘 멤버가 있을 가능성이 있음)인 경우 첫 번째 스니펫을 사용해야 합니다.그러면 기준을 어떻게 읽어도 절대로 틀릴 수 없습니다.

나는 다른 사람들이 말한 것처럼 그의 해결책이 표준에 따라 정의되지 않은 행동을 준다고 생각하기 때문에 Christ Dodd의 대답에 동의하지 않습니다.

"해결 방법"에 대해야 합니다.const정의되지 않은 동작을 호출하지 않는 방식의 한정자, 다음과 같은 해결책을 제안합니다.

  1. 정의하기void*a로 초기화된 변수malloc().러.
  2. 원하는 유형의 정의 및 개체, 이 경우struct deneme그리고 초기화를 할 수 있는 어떤 식으로const한정자는 (즉, 선언 줄 자체에서) 불평하지 않습니다.
  3. 사용하다memcpy()비트를 복사하다struct deneme에 반대하는void*물건.
  4. 포인터 선언struct deneme) 및 체)화l화)로 (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;
}

표준은 다음을 사용합니다.const키워드는 lvalue 한정자와 스토리지 클래스 사이의 이상한 하이브리드이지만 구조 구성원에게 어떤 의미가 적용될 수 있는지는 명확하게 밝히지 않습니다.

구조가 있는 경우s활자의struct S회원과m활자의T, s.foo유형의 l 값을 사용합니다.struct S그리고 유형의 가치에서 비롯됩니다.T.한다면T는 한정자를 포함하며, 해당 한정자는 이렇게 생성된 l 값에 영향을 미칩니다.

이 표준은 코드가 그렇지 않은 l 값을 취할 가능성을 확실히 인식하고 있습니다.const- 자격이 있는 경우, 다음 값으로부터 유도합니다.const-qualified, 원본과 마찬가지로 그렇지 않은 것에서 유도한 다음 l 값을 사용하여 개체를 수정합니다.확실하지 않은 것은 a의 사용 여부입니다.const구조 부재의 수식어는 객체의 기본 저장 클래스에 영향을 미치거나, 또는 그것이 단지 a를 야기할 것인지의 여부에 영향을 미칩니다.constmember-access 연산자를 사용하여 형성된 모든 l 값에 적용되는 modifier.전자는 모호하고 작동할 수 없는 구석 사례를 많이 초래하기 때문에 후자의 해석이 훨씬 더 일리가 있다고 생각하지만, 표준은 어떤 해석을 적용해야 하는지 명확하게 하지 않는다고 생각합니다.이 보지만, 어떤 위가 규정될 모든 상황은 후자의 해석상 동일하게 규정될 것이므로, 필자는 이 기준서의 저자들이 후자의 해석이 우월하다고 보지 않을 이유는 없다고 보지만, 어떤 경우에는, 어떤 구현에 있어서,이전의 해석은 위원회가 예측하지 못했던 몇 가지 이점을 제공할 수 있습니다.

언급URL : https://stackoverflow.com/questions/9691404/how-to-initialize-const-in-a-struct-in-c-with-malloc

반응형