2016-03-11 21 views
10

Trong hai báo cáo cuối cùng sau, bất kỳ sự khác biệt thực sự giữa các realPointerfakePointer. Cả hai đều cung cấp chức năng giống nhau không?Trong khi cố gắng để hiểu một con trỏ, tôi đã lo ngại

int num = 0; 

    int *realPointer = # 
    int fakePointer = # 
+34

Khi yêu cầu "thực hiện hai bit mã C này cung cấp cùng chức năng", vui lòng đăng mã thực sự biên dịch. Một trong các biến trên làm một cái gì đó, cái kia là một lỗi biên dịch-thời gian: rõ ràng, một lỗi thời gian biên dịch không có chức năng tương tự như một cái gì đó mà biên dịch. – Yakk

+0

@Yakk Với 'gcc' (ví dụ), đây chỉ là một cảnh báo, không phải là lỗi:' cảnh báo: khởi tạo làm cho số nguyên từ con trỏ mà không có một ký tự ' –

Trả lời

24
int fakePointer = # 

Đây không phải là hợp lệ C, nó vi phạm các quy tắc phân công đơn giản và sẽ không biên dịch. Tuy nhiên, bạn đã thực hiện int fakePointer = (int)# thì sự khác biệt duy nhất là không có đảm bảo rằng bạn có thể sử dụng giả mạo đáng tin cậy, chuyển đổi từ con trỏ đến số nguyên được xác định thực hiện và có khả năng dẫn đến hành vi chưa xác định (6.3.2.3) :

Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

Để an toàn và portably chuyển đổi giữa con trỏ và số nguyên, bạn không nên sử dụng int nhưng loại uintptr_t tìm thấy trong stdint.h.

+0

Vì lợi ích của OP có thể thêm kích thước con trỏ thường là 64 bit on, well, 64 bit architectures (bộ vi xử lý PC hiện đại với hệ điều hành 64 bit) trong khi ** 'int' kích cỡ thậm chí trên kiến ​​trúc 64 bit thường là 32 bit ** (gcc 4.9.3 trên x86_64 Cygwin/Windows 7/core i7 và Visual Studio 2013 nhắm mục tiêu x64, cùng PC). Trên các hệ thống như vậy, con trỏ -> int -> chuyển đổi con trỏ sẽ dẫn đến các địa chỉ không hợp lệ thiếu 32 bit cao hơn. –

+2

@ PeterA.Schneider Quan trọng hơn, 'int' là kiểu đã ký, nhưng không tồn tại địa chỉ tiêu cực. Vì vậy, nếu 'int' là 32 bit và kiểu con trỏ của bạn là 32 bit, nó sẽ không hoạt động hoặc là, bạn sẽ gọi hành vi không xác định khi chuyển đổi con trỏ có tập lệnh msb. – Lundin

+0

@Lundin: Tôi không nghĩ tiêu chuẩn C quan tâm đến việc có tồn tại địa chỉ tiêu cực hay không. Trong một nghĩa nào đó, các hệ thống x86-64 hiện tại sử dụng cả các địa chỉ ảo tích cực và tiêu cực, thường phân chia ở ranh giới người dùng/hạt nhân. –

4
int num = 0; 
int *realPointer = # 
int fakePointer = # 

In last two statements, any real difference between the realPointer and fakePointer.

bạn fakePointer KHÔNG phải là một con trỏ. Đó là một số nguyên với giá trị là địa chỉ của biến num. Bạn có thể lấy đi khi biên dịch này với các tùy chọn mặc định. Nhưng như Lundin đã chỉ ra, đây thực sự là một mã không hợp lệ. Sử dụng gcc với CFLAGS="-g -Wall -std=c99 -O3 -pedantic-errors" cờ, bạn sẽ nhận được lỗi này:

error: initialization makes integer from pointer without a cast 

Trong khi bạn realPointer thực sự trỏ đến biến num, và bạn có thể dereference nó. Bạn không thể làm gì giống như vậy với số fakePointer của mình - và trên thực tế việc gán cho chính mình là fakePointer không hợp lệ.

6

Biến được khai báo dưới dạng con trỏ có ngữ nghĩa khác với biến không được khai báo dưới dạng con trỏ. Trình biên dịch (và ngôn ngữ) sẽ cho phép bạn làm những việc với một con trỏ mà bạn không thể làm với một con trỏ không. Và ngược lại tất nhiên.

Chênh lệch lớn nhất là bạn có thể dereference một con trỏ, nhưng bạn không thể làm điều đó với một tổ chức phi-con trỏ.

Ví dụ, sử dụng các biến trong mã của bạn, sau đó chúng ta có thể làm để làm cho *realPointer = 5num được gán giá trị 5, nhưng làm *fakePointer = 5 là không được phép và không có ý nghĩa kể từ fakePointer không phải là thực sự là một con trỏ.

1

Nếu bạn đi cho các giá trị chữ (ví dụ giá trị thực tế) tổ chức bởi hai biến này, họ cùng (địa chỉ của num biến tức là.) Nhưng chỉ có giá trị như nhau. Nhưng như đã nói của những người khác họ ngữ nghĩa hai biến khác nhau và không thể được sử dụng thay thế cho nhau.

Đến với câu hỏi cuối cùng của bạn:

Cả hai đều có cùng chức năng không?

trả lời: Không, họ không.

Lý do chúng không cùng loại.

Câu hỏi đầu tiên của bạn:

bất kỳ sự khác biệt thực sự nào giữa realPointer và fakePointer.

Có rất nhiều sự khác biệt, và sự khác biệt cơ bản nhất là:

  1. realPointer giữ địa chỉ của num và là một con trỏ vì vậy nếu bạn thay đổi giá trị của num (bằng cách thay đổi sử dụng biến num hoặc * realPointer) nó được phản ánh ở cả hai nơi, nhưng nó không phải là trường hợp với fakePointer
  2. bạn có thể truyền realPointer cho các chức năng và bất kỳ thay đổi nào được thực hiện bên cạnh các cuộc gọi hàm sẽ được phản ánh trở lại hàm callee.
1

Bên cạnh thực tế rằng đây

int fakePointer = # 

có thể dẫn đến một hoặc nhiều các

  • hành vi undefined sau bằng cách phá vỡ "quy tắc" C ngôn ngữ (do đó có thể dẫn đến "bất cứ điều gì xảy ra")
  • mất các chữ số có nghĩa trong quá trình chuyển đổi
  • không biên dịch tại tất cả

Sự khác biệt sau đây được áp dụng:

  • Các * -/dereferencing-điều hành không thể bởi áp dụng cho các intfakePointer.
  • Làm fakePointer++ rất có khả năng sẽ dẫn đến điều gì đó khác biệt sau đó thực hiện realPointer++. Điều này áp dụng cho tất cả các cách cộng và trừ bất kỳ giá trị nào khác (nhưng 0). Đọc trên "pointer arithmetic" và "số học" để biết chi tiết.
  • Không thể áp dụng [] -/lập chỉ mục-toán tử cho số int đã nhập fakePointer.
Các vấn đề liên quan