2010-02-06 43 views
5

Chuyển đổi sau có an toàn không?Chuyển đổi không an toàn

int b[10][10]; 
char *x; 
int a[]={0,1,2,3,4,5,6,7,8,9}; 

for(int i=0;i<10;i++) 
    for(int j=0;j<10;j++) 
    b[i][j]=a[i]; 

for(x=(char *)&b[0];x<=(char *)&b[9][9];x+=sizeof(a+1)) // Problem lies here! 
    printf("%d\n",*x); 

Tôi không nghĩ chuyển đổi ở trên trong vòng lặp for là an toàn (tôi nghĩ nó phụ thuộc vào nền tảng). Hãy sửa tôi nếu tôi sai. Tôi ngạc nhiên vì mã biên dịch mà không đưa ra bất kỳ cảnh báo nào ngay cả khi được biên dịch bằng cách sử dụng các tùy chọn -Wall -pedantic trong gcc.

+0

'a', trong' a + 1' là gì? – GManNickG

+0

Tôi cho rằng đó là một sai lầm b. Tôi có thể sai mặc dù ... – Pod

+0

@GMan và @Pod: Đã chỉnh sửa! –

Trả lời

7

Toàn bộ điều này có khả năng là hợp pháp cho một và chỉ một lý do: đối tượng mảng 2D int được diễn giải lại dưới dạng mảng của đối tượng char. Trong khi trong trường hợp tổng quát lại bộ nhớ dẫn đến hành vi không xác định, các đặc tả ngôn ngữ rõ ràng cho phép "mảng của [đã ký/unsigned] char" reinterpretations cho các đối tượng của bất kỳ loại nào.

Tuy nhiên, vẫn còn một vấn đề an toàn chính thức. Ngôn ngữ không đảm bảo rằng bất kỳ mẫu bit nào là giá trị hợp lệ của loại char. Nỗ lực của bạn để đọc bộ nhớ được giải nghĩa thông qua loại char về mặt lý thuyết có thể gây ra hành vi không xác định nếu nó gặp đại diện bẫy cho char. Để an toàn ở đây, bạn phải sử dụng loại unsigned char, loại duy nhất không có biểu diễn cái bẫy. Tất nhiên, một nền tảng với bẫy char có thể được gọi là "kỳ lạ" một cách an toàn.

Trong khi đó, sizeof(a + 1) của bạn dường như không có ý nghĩa gì. a + 1 là biểu thức của loại int *. Tại sao bạn muốn sử dụng kích thước con trỏ để tăng giá trị x trong trường hợp này là không rõ ràng với tôi. Bạn đang cố gắng đạt được điều gì?

Vì không có cảnh báo ... Tôi không mong đợi trình biên dịch đưa ra bất kỳ cảnh báo nào tại đây. GCC thường cảnh báo về loại-punning (còn gọi là giải thích lại bộ nhớ), nhưng kể từ khi char reinterpretations được cho phép một cách rõ ràng (như tôi đã nói ở trên), không có cảnh báo ở đây. Hơn nữa, rõ ràng phôi thường có xu hướng ngăn chặn bất kỳ cảnh báo, vì họ là một cách để nói với trình biên dịch mà bạn thực sự muốn làm một cái gì đó bất kể như thế nào sai và/hoặc nguy hiểm nó có thể được.

+0

@Andrey T: _a + 1 là một biểu thức của int * type_ Và đó là những gì tôi muốn. Nó là một câu đố từ một cuộc cạnh tranh mã hóa trực tuyến. –

+1

@Prasoon: Bằng cách mà chu kỳ của bạn trông như thế nào, tôi hy vọng một cái sẽ sử dụng 'sizeof (int)' ở đây, như 'sizeof (a [1])' hoặc 'sizeof (* (a + 1))' hoặc ' sizeof (* a) '. Đối với 'sizeof (a + 1)', một lần nữa, tôi không hiểu điểm này là gì. Nó làm cho không có ý nghĩa với tôi. – AnT

+0

Tôi đã giả định sizeof (int) và sizeof (int *) giống nhau trên nền tảng cụ thể đó. Có, tôi nghĩ sizeof (* a) có vẻ chính xác hơn. –

1

một nhóm bất kỳ loại con trỏ nào vào char * được ngôn ngữ C. cho phép rõ ràng. vì vậy hầu hết điều này là tốt.

for(x=(char *)&b[0]; x <= (char *)&b[9][9]; x += sizeof(a+1)) 

Phần đầu tiên là phạt x = (char*)&b[0]; thiết lập con trỏ char vào đầu mảng. Bài kiểm tra cũng tốt x <= (char *)&b[9][9] sẽ là true miễn là x điểm bên trong mảng.

x += sizeof(a+1) là phần không rõ ràng. Trên hầu hết các cấu trúc CPU 32 bit sizeof (int *) chỉ xảy ra tương tự như sizeof (int), vì vậy mã này có thể là hoạt động, nhưng chỉ do ngẫu nhiên.

Tôi chắc chắn những gì được dự định là x += sizeof(a[0]) hoặc x += sizeof(b[0]), nhưng vì mã thực sự đã làm những gì được dự định, không ai nhận thấy lỗi.

Các vấn đề liên quan