2009-09-24 49 views
19

Tôi vừa đọc phần của C FAQ on pointers.Kích thước con trỏ có khác nhau giữa dữ liệu và con trỏ hàm không?

Thảo luận về việc không thể sử dụng các con trỏ chức năng vì các con trỏ tới dữ liệu và con trỏ đến hàm có thể có kích thước khác nhau trên một số nền tảng và void * chỉ đảm bảo đủ lớn để giữ con trỏ đến dữ liệu.

Có ai có thể đưa ra ví dụ về nền tảng trong đó con trỏ tới dữ liệu và con trỏ đến các hàm thực sự có kích thước khác nhau không?

+0

Bản sao của: http://stackoverflow.com/questions/916051/are-there-are-any-platforms-where-pointers-to-different-types-have-different-size – dmckee

+0

@dmckee, IMO, không một bản sao. – strager

+2

@strager: Không, bản gốc là * nhiều hơn * toàn diện. Nhưng điều này không nên bị xóa, bởi vì tôi nghi ngờ tiêu đề của nó có thể tìm kiếm được nhiều hơn, và có một số câu trả lời tốt – dmckee

Trả lời

11
> type ppp.c 
#include <stdio.h> 
#include <stdlib.h> 

int global = 0; 

int main(void) { 
    int local = 0; 
    static int staticint = 0; 
    int *mall; 
    int (*fx)(void); 

    fx = main; 
    mall = malloc(42); /* assume it worked */ 
    printf("#sizeof pointer to local: %d\n", (int)sizeof &local); 
    printf("#sizeof pointer to static: %d\n", (int)sizeof &staticint); 
    printf("#sizeof pointer to malloc'd: %d\n", (int)sizeof mall); 
    printf("#sizeof pointer to global: %d\n", (int)sizeof &global); 
    printf("#sizeof pointer to main(): %d\n", (int)sizeof fx); 
    free(mall); 
    return 0; 
} 
> tcc -mc ppp.c 
Turbo C Version 2.01 ... 
warnings about unused variables elided ... 
Turbo Link Version 2.0 ... 
> ppp 
#sizeof pointer to local: 4 
#sizeof pointer to static: 4 
#sizeof pointer to malloc'd: 4 
#sizeof pointer to global: 4 
#sizeof pointer to main(): 2 
> tcc -mm ppp.c 
> ppp 
#sizeof pointer to local: 2 
#sizeof pointer to static: 2 
#sizeof pointer to malloc'd: 2 
#sizeof pointer to global: 2 
#sizeof pointer to main(): 4 

tcc -mc tạo mã trong mô hình "nhỏ gọn"; tcc -mm tạo mã trong mô hình "trung bình"

+0

Tôi giả sử đây là máy X86? –

+4

... x86 chế độ thực 16 bit – Clifford

+0

Tôi nghĩ rằng đó là X86 ... Tôi không chắc chắn. Tôi chạy DOS bên trong một máy ảo trên một máy chủ Linux x86-64. – pmg

8

Trên chế độ thực x86, mã & dữ liệu được truy cập theo phân đoạn + bù trừ, mỗi số lượng 16 bit. Các con trỏ "gần" chỉ có 16 bit và sử dụng phân đoạn hiện tại, các con trỏ "Viễn" là 32 bit và chỉ định phân đoạn và độ lệch. Đối với các trình biên dịch C, có một số mô hình bộ nhớ khác nhau mà bạn có thể chọn, với các giá trị mặc định khác nhau của các con trỏ gần hoặc xa cho mã và dữ liệu.

Ví dụ: mô hình bộ nhớ "Trung bình" được sử dụng gần con trỏ cho dữ liệu nhưng con trỏ cho mã theo mặc định.

Tôi sẽ không ngạc nhiên nếu một số bộ vi xử lý nhúng hiện đại có mô hình bộ nhớ tương tự.

+0

Môi trường DOS và Windows cũ giống như thế này, với một số trình biên dịch. – Novelocrat

+2

@Pavel - Câu hỏi trực tiếp về con trỏ hàm và con trỏ dữ liệu, không phải giữa các kiểu dữ liệu khác nhau. – Michael

+1

Eh, tôi cần kính mắt mới: ( –

1

Đó là tình huống "phụ thuộc". Trong C++ tôi nhớ lại rằng các con trỏ hàm thành viên thực sự có hai con trỏ về kích thước, nhưng đó có thể chỉ là một chi tiết thực hiện.

Trong một số hệ thống pre-PC thực sự cũ bạn cũng có thể có kích thước con trỏ phụ thuộc vào những gì đã được tham khảo (nhưng sau đó bạn cũng có thể có nhân vật 11bit: D) ​​

+3

Nó hầu như không thể thực hiện một con trỏ hàm thành viên trong C++ trong ít hơn 2 từ máy; lý do là 1) gửi qua con trỏ thành viên phải là ảo, vì vậy bạn không thể chỉ lưu trữ địa chỉ của phương thức và 2) nó là hợp pháp để khai báo con trỏ thành viên cho các lớp được khai báo chuyển tiếp, vì vậy bạn không biết liệu lớp đó có bất kỳ phương thức ảo nào trước không. –

4

Máy móc sử dụng một Harvard Architecture có lưu trữ riêng biệt để biết hướng dẫn và dữ liệu và tương ứng có các không gian địa chỉ riêng biệt cho các hướng dẫn và dữ liệu. Trong một kiến ​​trúc như vậy, không có lý do thực sự để có hai không gian địa chỉ (hoặc bộ nhớ vật lý sao lưu chúng) có cùng kích thước.

+1

Nó có thể là tốt hơn để làm rõ tại sao đây là trường hợp thay vì chỉ liên kết đến Wikipedia. –

+0

Đủ công bằng; Tôi nghĩ rằng các văn bản Wikipedia là khá thông tin và nghĩ rằng nó đã đủ rõ ràng của riêng mình, nhưng những người hợp lý có thể khác nhau. –

+0

Trong khi đây là một con trỏ tốt (HA!) Cho OP, kiến ​​trúc Harvard không đòi hỏi sự khác biệt về kích thước con trỏ, kích thước của không gian địa chỉ. Bạn có thể có 2 ký tự vật lý riêng biệt được nhúng trong một không gian địa chỉ duy nhất, trong trường hợp đó bạn có thể không cần phải phân biệt giữa kích thước của void * s và kích thước của các con trỏ khác. Nhưng tôi đồng ý rằng một máy kiến ​​trúc Harvard là một nơi có khả năng để bắt đầu tìm kiếm một máy có dữ liệu riêng biệt và các con trỏ hàm. – Falaina

4

Bộ vi điều khiển PIC 16 bit (Microchip PIC24 và dsPIC) là các ví dụ về thiết bị kiến ​​trúc Harvard với các kích thước con trỏ không gian dữ liệu và mã khác nhau. Các không gian địa chỉ riêng biệt khác nhau về kích thước - trên chip SRAM có chi phí chip lớn hơn mà bộ nhớ Flash, có ít chi phí hơn, do đó con trỏ dữ liệu có thể nhỏ hơn.

Điều này cũng đúng với kiến ​​trúc PIC12, PIC16 và PIC18, nhưng dsPIC là điều tôi đang sử dụng hiện tại.

5

Lưu ý rằng POSIX đòi hỏi con trỏ đến đối tượng và con trỏ đến chức năng để có cùng kích thước:

2.12.3 Pointer loại

Tất cả các loại con trỏ hàm có các đại diện tương tự như con trỏ loại để void. Việc chuyển đổi một con trỏ hàm thành void * sẽ không thay đổi biểu diễn. Giá trị void * được tạo ra từ một chuyển đổi như vậy có thể được chuyển đổi về kiểu con trỏ hàm ban đầu, sử dụng một diễn viên rõ ràng, mà không làm mất thông tin.

Lưu ý: Tiêu chuẩn ISO C không yêu cầu điều này, nhưng nó là bắt buộc đối với sự tuân thủ POSIX.

Do đó, các hệ thống yêu cầu tuân thủ POSIX sẽ thống nhất. Nếu bạn chỉ nhắm mục tiêu các máy như vậy, thì bạn không phải lo lắng về sự khác biệt.

+4

NB: Kể từ 2013-03-07, phần này có vẻ bị thiếu trong POSIX [Loại dữ liệu] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_12), mặc dù nó là vẫn được đề cập trong [Lý do] (http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html#tag_22_02_12_03). Tôi đã yêu cầu làm rõ từ OpenGroup cho dù đây là một trục trặc trong trang web hoặc một sự thay đổi đáng kể trong POSIX 2013 so với POSIX 2008. Tôi không biết khi nào tôi sẽ nhận được câu trả lời. –

+0

bạn có bao giờ nhận được phản hồi không? – Mitch

+1

@Mitch: vâng, tôi nhận được phản hồi hồi tháng 3 năm 2014. Về cơ bản, đó là một sự thay đổi có chủ ý, phản hồi cho báo cáo lỗi. Các cuộc thảo luận về nó có sẵn tại http://austingroupbugs.net/view.php?id=74 nơi đoạn trích dẫn được loại bỏ và sửa đổi từ ngữ cho 'dlsym()' được mô tả. Đôi khi, tôi cần phải viết nó đúng cách - Tôi đã có ý nghĩa để làm điều đó cho hầu hết một năm nay (và các tuits tròn chưa bao giờ trở nên có sẵn). –

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