2012-03-13 43 views
19

Tôi đã thử;Cách khởi tạo const trong một cấu trúc trong C (với 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; 
} 

Và đây là trình biên dịch báo lỗi:

gereksiz.c:3:17: error: expected ':', ',', ';', '}' or '__attribute__' before '=' token 

Và, cũng này;

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; 
} 

Và đây là trình biên dịch báo lỗi:

gereksiz.c:10:5: error: assignment of read-only member 'a' 
gereksiz.c:11:5: error: assignment of read-only member 'b' 

Và không phải đã biên soạn. Có cách nào để khởi tạo một biến const bên trong một cấu trúc khi bộ nhớ phân bổ với malloc?

+0

@KerrekSB tất nhiên. – yasar

+0

@KerrekSB xem các chỉnh sửa của tôi. – yasar

+0

Bạn phải bỏ đi constness: '* (int *) (& mydeneme-> a) = 15;' –

Trả lời

18

Bạn cần phải ném cái const để khởi tạo các lĩnh vực của một cấu trúc malloc'ed:

struct deneme *mydeneme = malloc(sizeof(struct deneme)); 
*(int *)&mydeneme->a = 15; 
*(int *)&mydeneme->b = 20; 

Cách khác, bạn có thể tạo ra một phiên bản khởi tạo của cấu trúc và memcpy nó:

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

Bạn có thể làm cho deneme_init tĩnh và/hoặc toàn cầu nếu bạn làm điều này rất nhiều (vì vậy nó chỉ cần được xây dựng một lần).


Giải thích về lý do tại sao mã này không phải là hành vi không xác định theo đề nghị của một số các ý kiến, sử dụng tài liệu tham khảo tiêu chuẩn C11:

  • Mã này không vi phạm 6.7.3/6 vì không gian trở lại bởi malloc không phải là "một đối tượng được xác định với loại có đủ điều kiện". Biểu thức mydeneme->a không phải là một đối tượng, nó là một biểu thức. Mặc dù nó có loại const loại đủ điều kiện, nó biểu thị một đối tượng không được xác định bằng loại có đủ điều kiện const (trên thực tế, không được định nghĩa với bất kỳ loại nào).

  • Nguyên tắc răng cưa chặt chẽ là không bao giờ vi phạm bằng cách viết vào không gian được phân bổ bởi malloc, vì hiệu quả loại (6,5/6) được cập nhật theo từng ghi.

(Quy tắc bí danh nghiêm ngặt có thể bị vi phạm bằng cách đọc từ không gian được phân bổ bởi malloc).

Trong mẫu mã của Chris, giá trị đầu tiên đặt loại giá trị số nguyên thành int và thứ hai đặt loại hiệu dụng thành const int, tuy nhiên trong cả hai trường hợp, đọc các giá trị đó qua *mydeneme là chính xác vì quy tắc bí danh nghiêm ngặt (6.5/7 viên đạn 2) cho phép đọc một đối tượng thông qua một biểu thức bằng nhau hoặc có trình độ hơn so với loại hiệu quả của đối tượng. Kể từ khi biểu thức mydeneme->a có loại const int, nó có thể được sử dụng để đọc các đối tượng có hiệu lực loại intconst int.

+7

Không phải là hành vi truy cập không xác định truy cập const-cast? –

+8

* Rất * không xác định. –

+8

Không - const cast cũng được xác định nếu bộ nhớ được đề cập không phải là const (chẳng hạn như những gì xuất phát từ malloc). Nó chỉ không xác định nếu bạn cố gắng sửa đổi một đối tượng const thông qua các diễn viên. –

10

Bạn đã cố gắng làm như thế này:

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; 
} 

tôi đã không kiểm tra nhưng mã dường như đúng

1

Thú vị tôi tìm thấy con đường C99 này đang làm việc trong vang nhưng không phải trong gcc

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

Chào mừng bạn đến với Stack Overflow! Điều này có lẽ nên là một bình luận, nhưng nếu bạn có một câu hỏi mới, hãy hỏi nó bằng cách nhấn vào nút [Hỏi câu hỏi] (http://stackoverflow.com/questions/ask); bạn có thể muốn bao gồm một liên kết đến cái này cho ngữ cảnh. –

+2

@NathanTuggy nó trông giống như một câu trả lời cho tôi –

+0

@MattMcNabb: Có lẽ vậy; "không làm việc trong gcc" đề cập đã ném tôi đi. –

2

Tôi không đồng ý với số Câu trả lời của Christ Dodd, vì tôi nghĩ giải pháp của anh ta cho Hành vi không xác định theo các tiêu chuẩn, như những người khác nói.

Để "làm việc xung quanh" các const vòng trong một cách mà không gọi hành vi undefined, tôi đề xuất các giải pháp sau đây:

  1. Định nghĩa một biến void* khởi tạo với một cuộc gọi malloc().
  2. Xác định và đối tượng thuộc loại mong muốn, trong trường hợp này là struct deneme và khởi tạo nó theo cách nào đó mà mã loại const không khiếu nại (nghĩa là, trong chính dòng tuyên bố).
  3. Sử dụng memcpy() để sao chép các bit của đối tượng struct deneme đối tượng void*.
  4. Khai báo một con trỏ đến struct deneme đối tượng và khởi tạo nó thành biến số (void*), trước đây được truyền tới (struct deneme *).

Vì vậy, mã của tôi sẽ là:

#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; 
} 
Các vấn đề liên quan