2015-02-17 16 views
9

Tôi hiện đang theo học trong một lớp CS107 mà làm cho các giả định sau:Pointer số học xung quanh đúc

  • sizeof(int) == 4
  • sizeof(short) == 2
  • sizeof(char) == 1
  • endianness lớn

giáo sư của tôi cho thấy đoạn mã sau:

int arr[5]; 
((short*)(((char*) (&arr[1])) + 8))[3] = 100; 

Dưới đây là 20 byte đại diện cho arr:

|....|....|....|....|....| 

giáo sư của tôi nói rằng &arr[1] điểm ở đây, mà tôi đồng ý với.

|....|....|....|....|....| 
    x 

bây giờ tôi hiểu rằng (char*) làm cho con trỏ chiều rộng của một char (1 byte) thay vì chiều rộng của một int (4 byte).

Những gì tôi không hiểu là + 8, mà giáo sư của tôi nói điểm ở đây:

|....|....|....|....|....| 
         x 

Nhưng không nên nó chỉ ở đây, vì nó sẽ chuyển tiếp 8 lần so với kích thước của một char (1 byte)?

|....|....|....|....|....| 
       x 
+6

Bạn nói đúng.Viết một số mã để in các giá trị của con trỏ để cho giáo sư thấy rằng bạn đúng. –

+3

Tất cả phụ thuộc vào 'sizeof (int)', mà không nhất thiết là '4'. –

+2

@BlagovestBuyukliev Giáo sư của tôi đã tuyên bố giả sử rằng 'sizeof (int)' là 4 trong suốt thời gian của lớp. Xin lỗi, tôi nên đề cập đến điều đó. – Alexey

Trả lời

4

Hãy thực hiện từng bước. biểu hiện của bạn có thể bị phân hủy như thế này:

((short*)(((char*) (&arr[1])) + 8))[3] 
----------------------------------------------------- 
char *base = (char *) &arr[1]; 
char *base_plus_offset = base + 8; 
short *cast_into_short = (short *) base_plus_offset; 
cast_into_short[3] = 100; 

base_plus_offset điểm tại byte vị trí 12 trong mảng. cast_into_short[3] đề cập đến giá trị short tại vị trí 12 + sizeof(short) * 3, trong trường hợp của bạn là 18.

+3

Và đó là lý do tại sao mã như thế không nên được viết trên một dòng. Ở đây nó là tinh thể rõ ràng những gì đang xảy ra. Trong đoạn mã trong câu hỏi, tôi cho rằng giáo sư tự nhầm lẫn với quá nhiều dấu ngoặc đơn. – gnasher729

+1

@ gnasher729: Hoặc ít nhất là tránh những parens vô dụng như '(char *) (& arr [1])' (có vẻ như ở đây cho mọi người không biết rằng một diễn viên có thể có một biểu hiện đơn nhất, cái gì, nếu nó không cho phép, sẽ không biên dịch mà không có parens anyway, nghi ngờ này "làm rõ" thậm chí không thể được thể hiện trong điều kiện ưu tiên). Mặc dù tôi đồng ý rằng nó có lẽ nên được phân chia trong trường hợp này. – mafso

+1

@mafso: Cặp ngoặc đơn thứ hai cũng vô dụng, do đó, phiên bản không chứa hàng hóa của biểu thức đó sẽ là: '((ngắn *) ((char *) & arr [1] + 8)) [3]' . –

1

Dưới đây là một số mã có thể cho bạn thấy những byte được sửa đổi trên hệ thống của bạn, cùng với phân tích về những gì đang xảy ra:

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    int arr[5]; 
    int i; 

    for(i = 0; i < 5; i++) 
     arr[i] = 0; 

    printf("Before: "); 

    for(i = 0; i < sizeof(int)*5; i++) 
     printf("%2.2X ", ((char*)arr)[i]); 

    printf("\n"); 

    ((short*)(((char*) (&arr[1])) + 8))[3] = 100; 

    printf("After: "); 

    for(i = 0; i < sizeof(int)*5; i++) 
     printf("%2.2X ", ((char*)arr)[i]); 
    printf("\n"); 

    return 0; 
} 

Bắt đầu từ bên trong nhất:

int con trỏ đến (arr + 4)

&arr[1] 
|...|...|...|...|... 
    Xxxx 

char trỏ đến (arr + 4)

(char*)(&arr[1]) 
|...|...|...|...|... 
    X 

con trỏ char đến (arr + 4 + 8)

((char*)(&arr[1])) + 8) 
|...|...|...|...|... 
      X 

con trỏ ngắn đến (arr + 4 + 8)

(short*)((char*)(&arr[1])) + 8) 
|...|...|...|...|... 
      Xx 

ngắn tại (arr + 4 + 8 + (3 * 2)) (đây là chỉ số mảng)

((short*)((char*)(&arr[1])) + 8))[3] 
|...|...|...|...|... 
        Xx 

Chính xác byte nào được sửa đổi ở đây tùy thuộc vào độ cuối của hệ thống của bạn. Trên x86 nhỏ cuối của tôi, tôi nhận được kết quả sau:

Before: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
After: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 00 

Chúc may mắn với khóa học của bạn.

+1

Phân tích của bạn về biểu thức là chính xác, nhưng dường như bạn đã hiểu lầm tuyên bố của OP khi bạn nói rằng anh ấy không đúng. Chỉnh sửa (một, cho đến nay) của anh ta không tạo ra sự khác biệt nào, vì phép thêm vào 'short *' không phải là một phần của biểu thức con mà anh ta đang tìm hiểu. –

+0

@JohnBollinger Cảm ơn, tôi đã sửa lại tuyên bố đó! Cũng thêm vào vị trí con trỏ và cách sử dụng bộ nhớ. –

1

Khái niệm sẽ thiết lập hai byte 18 byte sau khi bắt đầu arr với giá trị 100.

#include <stdio.h> 

int main() { 

    int arr[5]; 

    char* start=(char*)&arr; 
    char* end=(char*)&((short*)(((char*) (&arr[1])) + 8))[3]; 

    printf("sizeof(int)=%zu\n",sizeof(int)); 
    printf("sizeof(short)=%zu\n",sizeof(short)); 
    printf("offset=%td <- THIS IS THE ANSWER\n",(end-start)); 
    printf("100=%04x (hex)\n",100); 

    for(size_t i=0;i<5;++i){ 

     printf("arr[%zu]=%d (%08x hex)\n",i,arr[i],arr[i]); 

    } 

} 

thể Output:

sizeof(int)=4 
sizeof(short)=2 
offset=18 <- THIS IS THE ANSWER 
100=0064 (hex) 
arr[0]=0 (00000000 hex) 
arr[1]=0 (00000000 hex) 
arr[2]=0 (00000000 hex) 
arr[3]=0 (00000000 hex) 
arr[4]=6553600 (00640000 hex) 

Trong tất cả shenanigans giáo sư của bạn anh ấy chuyển cho bạn 1 số nguyên , 8 ký tự/byte và 3 đoạn có 4 + 8 + 6 = 18 byte. Chơi lô tô.

Lưu ý đầu ra này cho thấy máy tôi chạy trên có số nguyên 4 byte, ngắn 2 byte (thường) và ít kết thúc vì hai byte cuối cùng của mảng được đặt thành 0x64 và 0x00 tương ứng.

Tôi thấy sơ đồ của bạn gây nhầm lẫn đáng sợ vì không rõ ràng nếu bạn có ý nghĩa '|' là địa chỉ hay không.

|....|....|....|....| 

    ^ 1^ ^2 
A X  C  S B 

Bao gồm các thanh ('|') A là sự bắt đầu của Arr và B là 'một quá khứ cuối' (một khái niệm pháp lý trong C).

X là địa chỉ được tham chiếu bởi biểu thức & Arr [1]. C bằng biểu thức (((char *) (& arr [1])) + 8). S bằng toàn bộ biểu thức. S và các byte sau được gán cho và điều đó có nghĩa là phụ thuộc vào endian-ness của nền tảng của bạn.

Tôi để nó như là một bài tập để xác định đầu ra trên nền tảng tương tự nhưng lớn cuối cùng nào xuất ra. Bất kỳ ai? Tôi nhận thấy từ các ý kiến ​​bạn là người lớn tuổi và tôi là người ít tuổi (ngừng cười khúc khích). Bạn chỉ cần thay đổi một dòng đầu ra.

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