2011-02-28 30 views
17

Ai đó có thể vui lòng giải thích chính xác lý do tại sao typedef s/#define giây sau đây đã được xác định? Họ có giá trị gì so với bản gốc?Các loại dữ liệu Windows ... tại sao lại dư thừa/không mô tả?

typedef char CHAR; 
#define CONST const 
typedef float FLOAT; 

typedef unsigned __int64 DWORD64; //A 64-bit "double"-word?! 
typedef ULONGLONG DWORDLONG;  //What's the difference? 

typedef ULONG_PTR DWORD_PTR;  //What's the difference? 
typedef long LONG_PTR;   //Wasn't INT_PTR enough? 

typedef signed int LONG32;  //Why not "signed long"? 
typedef unsigned int UINT;  //Wait.. UINT is "int", "LONG" is also int? 
typedef unsigned long ULONG;  //ULONG is "long", but LONG32 is "int"? what? 

typedef void *PVOID;    //Why not just say void*? 
typedef void *LPVOID;    //What?! 

typedef ULONG_PTR SIZE_T;   //Why not just size_t? 

Và tốt nhất của tất cả:

#define VOID void     //Assuming this is useful (?), why not typedef? 

lý do đằng sau những gì? Có một số loại trừu tượng mà tôi không hiểu?


Sửa:

Đối với những người nhắc đến trình biên dịch chéo compatilibity:

Câu hỏi của tôi là không về việc tại sao họ không sử dụng unsigned long long thay vì, nói, DWORD64. Câu hỏi của tôi là về lý do tại sao mọi người sử dụng DWORD64 thay vì ULONG64 (hoặc ngược lại)? Không phải cả hai trong số đó là typedef có chiều rộng là 64 bit không?

Hoặc, như một ví dụ khác: Ngay cả trong trình biên dịch "giả thiết" có nghĩa là đánh lừa chúng ta trong mọi khía cạnh, sự khác biệt giữa ULONG_PTRUINT_PTRDWORD_PTR là gì? Không phải tất cả các loại dữ liệu trừu tượng này đều có cùng ý nghĩa - SIZE_T?

Tuy nhiên, tôi hỏi lý do tại sao họ đã sử dụng ULONGLONG thay vì long long - là có bất kỳ sự khác biệt tiềm năng trong ý nghĩa, được bao phủ bởi không long long cũng không DWORDLONG?

+1

Tôi sẽ nghi ngờ rất nhiều những harken từ độ tuổi tối tăm của win16, nhưng tôi sẽ để lại cho những người thực sự đã viết mã cửa sổ trở lại trong thời đại của yore để trả lời :) – bdonlan

+0

@bdonlan: Haha okay. :) – Mehrdad

+0

Có rất nhiều điều ảnh hưởng đến lịch sử của các loại này. Khi đã xác định một lần, bạn không bao giờ có thể lấy lại. #define VOID void đã được thực hiện, vì ban đầu void * ban đầu không có trong tiêu chuẩn C (không thể tìm thấy một liên kết ...). Vì vậy, một số trình biên dịch đã không nhận ra nó. Nhưng nếu bạn loại bỏ nó ngay bây giờ, bạn phá vỡ mã. Và không ai muốn ngắt mã của mình, khi cập nhật SDK. Đã có quá nhiều vấn đề khi cập nhật, tại sao lại phá vỡ điều này trong một số mô-đun cũ mà không được xúc động cho 'thế kỷ' nhưng bây giờ đột nhiên không biên dịch nữa. – Christopher

Trả lời

18

Hầu hết các tên dư thừa tồn tại chủ yếu vì hai lý do:

  • họ đang loại lịch sử được bảo tồn cho tương thích ngược
  • họ tên khác nhau cho cùng một loại nảy sinh từ các đội khác nhau của các nhà phát triển (nó có thể là đáng ngạc nhiên khó khăn cho các đội để duy trì ổn định qua một dự án như vậy khổng lồ như Windows)

typedef char CHAR; 

Sự ký kết của char có thể khác nhau giữa các nền tảng và trình biên dịch, vì vậy đó là một lý do. Các nhà phát triển ban đầu có thể cũng đã giữ này mở cho những thay đổi trong tương lai trong mã hóa ký tự, nhưng tất nhiên điều này không còn liên quan vì chúng tôi sử dụng TCHAR ngay bây giờ cho mục đích đó.


typedef unsigned __int64 DWORD64; //A 64-bit "double"-word?! 

Trong di chuyển đến 64-bit, họ có thể phát hiện ra rằng một số DWORD lập luận của họ thực sự cần thiết để được 64 bit dài, và họ có thể đổi tên nó DWORD64 để người dùng hiện có của những API weren' t nhầm lẫn.


Cái này ngày trở lại vào những ngày 16-bit, khi có thường xuyên gợi ý "gần" mà là 16-bit và "xa" gợi ý rằng 32-bit. Các L prefix trên các loại viết tắt của "dài" hay "xa", mà là vô nghĩa bây giờ, nhưng trở lại trong những ngày đó, chúng được thể định nghĩa như thế này:

typedef void near *PVOID; 
typedef void far *LPVOID; 

Cập nhật: Đối với FLOAT , UINTULONG, đây chỉ là ví dụ về "trừu tượng hơn là tốt", theo quan điểm của những thay đổi trong tương lai. Hãy nhớ rằng Windows cũng chạy trên các nền tảng khác với x86 - bạn có thể nghĩ về một kiến ​​trúc nơi các số dấu phẩy động được biểu diễn ở định dạng không chuẩn và các hàm API được tối ưu hóa để sử dụng biểu diễn này. Điều này có thể xung đột với loại dữ liệu float của C.

+0

+1 Giải thích tuyệt vời! Còn về 'FLOAT',' UINT' và 'ULONG' thì sao? Tại sao không chỉ sử dụng 'float',' unsigned int', và 'unsigned long'? (Là 'UINT' và' ULONG' có kích thước cố định?) Oh, và là 'CHAR' đã ký hoặc chưa ký rồi? – Mehrdad

+0

@Mehrdad: Xem cập nhật của tôi. Bây giờ bạn hỏi nó, tôi không chắc chắn về sự ký kết của 'CHAR' - câu trả lời của tôi đầy đoán, nhưng đó là điều tốt nhất tôi có thể làm. – casablanca

+1

@casablanca: Er ... làm thế nào là 'INT'" trừu tượng hơn "hơn' int'? Và, bạn có thể đưa ra ví dụ về cách giới thiệu 'FLOAT' * có thể * hữu ích trên các nền tảng và/hoặc trình biên dịch, ngay cả trong một ý nghĩa lý thuyết, từ xa? – Mehrdad

1

Một lý do là duy trì một số loại tính di động giữa các trình biên dịch C.

Trong DWORD64 cụ thể, về lý thuyết bạn chỉ cần thay đổi định nghĩa của DWORD64 để lấy mã biên dịch trên các trình biên dịch khác.

+0

Tại sao không chỉ sử dụng 'ULONG64' ở khắp mọi nơi? Còn phần còn lại, như 'VOID' thì sao? (Tôi đã hỏi về cả dự phòng trong các định nghĩa * và * về số lượng typedef ... có lý do gì không, ngay cả trong lý thuyết, để sử dụng 'DWORD64' thay vì' ULONG64'?) – Mehrdad

+1

Trình biên dịch khác nhau có khác nhau "được xây dựng trong "tên cho số nguyên 64 bit. Các typedef VOID có vẻ hơi vô nghĩa mặc dù - không thể giải thích rằng một. – Jimmy

+0

@Jimmy: Câu hỏi của tôi không phải là lý do tại sao họ không sử dụng 'unsigned long long'; câu hỏi của tôi là về lý do tại sao mọi người sẽ sử dụng 'DWORD64' thay vì' ULONG64' (hoặc ngược lại)? Không phải * cả hai * trong số đó được đánh máy là 64 bit? – Mehrdad

9

Khi tệp tiêu đề Windows API được tạo lần đầu tiên cách đây 25 năm, một int là 16 bit và long là 32 bit. Các tệp tiêu đề đã phát triển theo thời gian để phản ánh các thay đổi trong trình biên dịch và phần cứng.

Ngoài ra, Microsoft C++ không phải là trình biên dịch C++ duy nhất hiện có hoạt động với các tệp tiêu đề Windows. Khi Microsoft thêm từ khóa size_t, không phải tất cả trình biên dịch đều hỗ trợ nó. Nhưng họ có thể dễ dàng tạo macro, SIZE_T để thể hiện.

Ngoài ra, còn có (hoặc là) công cụ tự động chuyển đổi tệp tiêu đề API từ C/C++ sang các ngôn ngữ khác. Nhiều người trong số những công cụ này ban đầu được viết để làm việc với các định nghĩa tiêu đề hiện tại (tại thời điểm). Nếu Microsoft chỉ thay đổi các tệp tiêu đề để sắp xếp chúng như bạn đề xuất, nhiều công cụ đó sẽ ngừng hoạt động.

Về cơ bản, tệp tiêu đề ánh xạ các loại Windows thành mẫu số chung ít nhất để nhiều công cụ có thể làm việc với chúng. Nó dường như là một thứ lộn xộn vào thời điểm nào đó, và tôi nghi ngờ rằng nếu Microsoft sẵn sàng ném ra bất kỳ khả năng tương thích ngược nào, họ có thể giảm một phần lớn sự hỗn độn. Nhưng làm như vậy sẽ phá vỡ rất nhiều công cụ (chưa kể nhiều tài liệu).

Vì vậy, có, các tệp tiêu đề của Windows đôi khi là một mớ hỗn độn. Đó là cái giá mà chúng tôi phải trả cho sự tiến hóa, khả năng tương thích ngược và khả năng làm việc với nhiều ngôn ngữ.

Thông tin bổ sung:

Tôi sẽ đồng ý rằng ngay từ cái nhìn đầu tiên tất cả các định nghĩa đó có vẻ điên rồ. Nhưng là một trong những người đã nhìn thấy các tập tin tiêu đề Windows phát triển theo thời gian, tôi hiểu làm thế nào họ đến. Hầu hết các định nghĩa đó đều có ý nghĩa hoàn hảo khi chúng được giới thiệu, ngay cả bây giờ chúng trông điên rồ. Đối với trường hợp cụ thể ULONGLONGDWORD64, tôi tưởng tượng rằng chúng đã được thêm vào để nhất quán, vì các tệp tiêu đề cũ có ULONGDWORD, vì vậy các lập trình viên sẽ mong đợi hai thiết bị kia. Còn về lý do ULONGDWORD đều đã được xác định khi họ là những điều tương tự, tôi có thể nghĩ ra một vài khả năng, hai trong số đó là:

  • Một đội API được sử dụng ULONG và khác sử dụng DWORD, và khi tập tin tiêu đề là hợp nhất họ chỉ giữ cả hai thay vì phá vỡ mã bằng cách chuyển đổi sang một hoặc khác.
  • Một số nhà lập trình có suy nghĩ thoải mái hơn về mặt số ULONG hơn DWORD. ULONG ngụ ý một loại số nguyên mà bạn có thể thực hiện toán học, trong khi DWORD chỉ ngụ ý giá trị 32 bit chung của một số loại, thường là một khóa, giá trị hoặc giá trị khác mà bạn không muốn sửa đổi.

Câu hỏi ban đầu của bạn là liệu có một số lý do đằng sau các định nghĩa có vẻ điên rồ hay không, hoặc nếu có một trừu tượng bạn không bỏ sót. Câu trả lời đơn giản là các định nghĩa đã phát triển, với những thay đổi có ý nghĩa vào thời điểm đó. Không có trừu tượng cụ thể, mặc dù ý định là nếu bạn viết mã của mình để sử dụng các loại được xác định trong tiêu đề, thì bạn nên có thể chuyển mã của bạn từ 32 bit sang 64 bit mà không gặp sự cố. Tức là, DWORD sẽ giống nhau ở cả hai môi trường. Nhưng nếu bạn sử dụng DWORD cho giá trị trả về khi API cho biết giá trị trả lại là HANDLE, bạn sẽ gặp sự cố.

+0

Cảm ơn bạn đã phản hồi, nhưng vui lòng xem chỉnh sửa của tôi.Câu hỏi của tôi không phải là lý do tại sao họ không sử dụng các kiểu dữ liệu tích hợp (mà rõ ràng là khác nhau bởi trình biên dịch ... ngoại trừ 'void', cái đó làm tôi bối rối), nhưng tại sao chúng lại có nhiều tên cho cùng kiểu dữ liệu trừu tượng , chẳng hạn như 'DWORD64' và 'ULONG64' cho" số nguyên có chiều rộng 64 bit ". Tại sao một ** khách hàng ** chọn 'ULONG_PTR' trên' UINT_PTR' hoặc 'DWORDLONG' trên' ULONGLONG' hoặc 'DWORD64' hoặc' ULONG64'? – Mehrdad

+0

@ Mehrdad - bởi vì không có gì trong tiêu chuẩn nói rằng lớn như thế nào lâu dài (khác hơn là nó phải có ít nhất là lớn như một int). DWORD64 là 64bits trên bất cứ điều gì từ một cửa sổ 16bit đến một 128bit Cray –

+0

@Marting: Chờ đợi, nhưng sau đó sự khác biệt giữa 'ULONG64' và' ULONGLONG' là gì? Nếu 'ULONG64' luôn là 64 bit, thì tại sao không sử dụng' DWORD64'? Và nếu nó * không * luôn luôn 64 bit, thì tại sao không sử dụng 'ULONGLONG'? – Mehrdad

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