Kiến trúc kỳ lạ mà các ủy ban tiêu chuẩn quan tâm


154

Tôi biết rằng các tiêu chuẩn C và C ++ để lại nhiều khía cạnh của việc triển khai ngôn ngữ - được định nghĩa chỉ vì nếu có một kiến ​​trúc với các đặc điểm khác, sẽ rất khó hoặc không thể viết trình biên dịch tuân thủ tiêu chuẩn cho nó.

Tôi biết rằng 40 năm trước, bất kỳ máy tính nào cũng có thông số kỹ thuật độc đáo của riêng nó. Tuy nhiên, tôi không biết bất kỳ kiến ​​trúc nào được sử dụng ngày nay:

  • CHAR_BIT != 8
  • signed không phải là bổ sung của hai (tôi nghe nói Java có vấn đề với cái này).
  • Điểm nổi không tuân thủ theo chuẩn IEEE 754 (Chỉnh sửa: Ý tôi là "không có trong mã hóa nhị phân của IEEE 754").

Lý do tôi hỏi là tôi thường giải thích cho mọi người rằng nó tốt mà C ++ không ban hành bất kỳ khía cạnh cấp thấp khác như các loại có kích thước cố định . Điều này tốt bởi vì không giống như 'các ngôn ngữ khác', nó làm cho mã của bạn có thể di động khi được sử dụng một cách chính xác (Chỉnh sửa: bởi vì nó có thể được chuyển sang nhiều kiến ​​trúc hơn mà không yêu cầu mô phỏng các khía cạnh cấp thấp của máy, ví dụ như hai số học bổ sung về ký hiệu + kiến ​​trúc cường độ) . Nhưng tôi cảm thấy tồi tệ rằng tôi không thể chỉ vào bất kỳ kiến ​​trúc cụ thể nào.

Vì vậy, câu hỏi là: kiến ​​trúc nào thể hiện các tính chất trên?

uint*_ts là không bắt buộc.


9
Tôi nghĩ rằng bạn có nó ngược. Nếu C ++ là bắt buộc, giả sử, twos bổ sung cho các số nguyên đã ký, nó sẽ làm cho mã C ++ dễ mang theo hơn không ít. Câu hỏi tại sao ủy ban tiêu chuẩn C ++ không bắt buộc đây là một vấn đề khác. Đặc biệt, bất chấp những gì bạn nói, sẽ không thể viết trình biên dịch cho kiến ​​trúc không chuẩn, bạn luôn có thể mô phỏng ký tự 8 bit hoặc twos bổ sung cho số học ngay cả khi nền tảng của bạn không hỗ trợ trực tiếp.
john

8
@john: thì nó sẽ không thực tế nên trình biên dịch tuân thủ không chuẩn sẽ tạo mã nhanh hơn so với trình biên dịch tuân thủ. Và tôi vẫn không thấy cách nó làm cho mã của bạn dễ di chuyển hơn.
Yakov Galka

4
Tôi chắc chắn lý do thực sự cho tiêu chuẩn như vậy không phải vì đó là một giải pháp lý tưởng. Nhưng thay vào đó là vì khi tiêu chuẩn được viết, nhiều trình biên dịch C và C ++ đã tồn tại và ủy ban tiêu chuẩn không muốn từ chối các trình biên dịch hiện có.
john

4
@john: Tôi nghi ngờ rằng "làm cho trình soạn thảo trình biên dịch dễ dàng hơn" là ưu tiên khi tạo tiêu chuẩn C ++ (họ sẽ làm một công việc tồi tệ nếu như vậy, vì C ++ là một trong những ngôn ngữ khó phân tích nhất và các khía cạnh khác của ngôn ngữ không chính xác làm cho trình biên dịch dễ dàng hơn). Hiệu suất, hỗ trợ nền tảng rộng và khả năng tương thích ngược là khá quan trọng. Và tất cả ba người đó sẽ phải chịu đựng nếu (các) hạn chế mà bạn đề cập sẽ được thêm vào tiêu chuẩn.
Sander De Dycker

5
Nó không phải là về trình biên dịch mà là phần cứng. C ++ để lại một số thứ không xác định để cho phép sử dụng trực tiếp các tính năng phần cứng. Các ứng dụng điện thoại của bạn sẽ không chạy trên máy tính lớn, vì vậy không có tính di động tuy nhiên tuân thủ mã.
Bo Persson

Câu trả lời:


114

Hãy nhìn vào cái này

Máy chủ Unisys ClearPath Dorado

cung cấp khả năng tương thích ngược cho những người chưa di chuyển tất cả phần mềm Univac của họ.

Những điểm chính:

  • Từ 36 bit
  • CHAR_BIT == 9
  • bổ sung của một
  • Điểm nổi 72-bit không phải của IEEE
  • không gian địa chỉ riêng cho mã và dữ liệu
  • địa chỉ từ
  • không có con trỏ ngăn xếp chuyên dụng

Không biết họ có cung cấp trình biên dịch C ++ hay không, nhưng họ có thể .


Và bây giờ, một liên kết đến một phiên bản gần đây của hướng dẫn sử dụng C của họ đã xuất hiện:

Hướng dẫn tham khảo lập trình trình biên dịch Unisys C

Mục 4.5 có một bảng các loại dữ liệu với 9, 18, 36 và 72 bit.

kích thước và phạm vi của các loại dữ liệu trong trình biên dịch USC C


13
Tôi đoán void * phải là địa ngục để sử dụng trong kiến ​​trúc đó.
luiscubal

13
@ybungalobill - Tôi tin char*void*phải có cùng kích thước, và đủ lớn để chứa bất kỳ con trỏ nào khác. Phần còn lại là tùy thuộc vào việc thực hiện.
Bo Persson

22
@ybungalobill: Trên các trình biên dịch Win16 cũ, các con trỏ thông thường gần các con trỏ và chỉ chứa một phần bù 16 bit, vì vậy sizeof(int*) == 2, các con trỏ xa cũng có bộ chọn 16 bit, vì vậy sizeof(void*) == 4.
Adam Rosenfield

10
Có, hoặc đã từng là một hướng dẫn trực tuyến cho trình biên dịch C ++ của họ. Cũng đáng để chỉ ra rằng đây chỉ là một trong những kiến ​​trúc máy tính lớn của Unisys: cái kia là kiến ​​trúc được gắn thẻ có cường độ 48 bit (mà tôi chỉ tìm thấy hướng dẫn sử dụng C, không phải là C ++). Liên quan đến phần còn lại: Tôi không nghĩ rằng sizeof(int*) != sizeof(char*)ở đây: cả hai đều là 36 bit. Nhưng bộ chọn byte trong char*là trên các bit thứ tự cao và bị bỏ qua int*. (Tuy nhiên, tôi đã sử dụng các máy khác, trong đó `sizeof (char *)> sizeof (int *).)
James Kanze

16
@Adam Rosenfield Trên trình biên dịch 16 bit của MS / DOS, bạn có các "chế độ" khác nhau và các con trỏ dữ liệu không nhất thiết phải có cùng kích thước với các con trỏ hàm. Nhưng ít nhất trên những cái tôi đã sử dụng, tất cả các con trỏ dữ liệu (bao gồm void*) luôn có cùng kích thước. (Tất nhiên, bạn không thể chuyển đổi một con trỏ hàm thành void*, vì void*có thể nhỏ hơn. Nhưng theo tiêu chuẩn, bạn cũng không thể làm điều đó ngay hôm nay.)
James Kanze

51

Không có giả định nào của bạn giữ cho máy tính lớn. Để bắt đầu, tôi không biết về một máy tính lớn sử dụng IEEE 754: IBM sử dụng điểm nổi cơ sở 16 và cả hai máy tính lớn của Unisys đều sử dụng cơ sở 8. Các máy Unisys hơi đặc biệt ở nhiều khía cạnh khác: Bo đã đề cập đến 2200 kiến trúc, nhưng kiến ​​trúc MPS thậm chí còn xa lạ: các từ được gắn thẻ 48 bit. (Từ đó có phải là con trỏ hay không phụ thuộc vào một chút trong từ.) Và các biểu diễn số được thiết kế sao cho không có sự phân biệt thực sự giữa dấu phẩy động và số học tích phân: dấu phẩy động là cơ sở 8; nó không yêu cầu chuẩn hóa, và không giống như mọi điểm nổi khác mà tôi đã thấy, nó đặt số thập phân ở bên phải của lớp phủ, thay vì bên trái và sử dụng cường độ đã ký cho số mũ (ngoài lớp phủ). Với các kết quả mà một giá trị dấu phẩy động tích phân có (hoặc có thể có) chính xác biểu diễn bit giống như một số nguyên cường độ đã ký. Và không có hướng dẫn số học dấu phẩy động: nếu số mũ của hai giá trị đều bằng 0, thì lệnh này không tính số học tích phân, nếu không, nó thực hiện số học dấu phẩy động. (Tiếp nối triết lý gắn thẻ trong kiến ​​trúc.) Có nghĩa là trong khiint có thể chiếm 48 bit, 8 trong số chúng phải là 0 hoặc giá trị sẽ không được coi là số nguyên.


4
Các máy tính lớn của IBM (z / Architecture) không hỗ trợ điểm nổi IEE754.
Nikita Nemkin


6
@Nikita - Họ làm ngay bây giờ . Ban đầu nó là một add-on (đắt tiền) để hỗ trợ Java.
Bo Persson


42

Tuân thủ đầy đủ IEEE 754 là rất hiếm trong triển khai điểm nổi. Và làm suy yếu đặc điểm kỹ thuật trong vấn đề đó cho phép rất nhiều tối ưu hóa.

Ví dụ, sự khác biệt hỗ trợ subnorm giữa x87 và SSE.

Tối ưu hóa như hợp nhất một phép nhân và phép cộng riêng biệt trong mã nguồn cũng làm thay đổi kết quả một chút, nhưng tối ưu hóa tốt trên một số kiến ​​trúc.

Hoặc trên x86, việc tuân thủ nghiêm ngặt của IEEE có thể yêu cầu một số cờ nhất định được đặt hoặc chuyển bổ sung giữa các thanh ghi dấu phẩy động và bộ nhớ thông thường để buộc nó sử dụng loại dấu phẩy động được chỉ định thay vì các phao nổi 80 bit bên trong.

Và một số nền tảng hoàn toàn không có phần cứng nổi và do đó cần phải mô phỏng chúng trong phần mềm. Và một số yêu cầu của IEEE 754 có thể tốn kém khi thực hiện trong phần mềm. Cụ thể, các quy tắc làm tròn có thể là một vấn đề.

Kết luận của tôi là bạn không cần các kiến ​​trúc kỳ lạ để có thể rơi vào tình huống là bạn không luôn muốn đảm bảo tuân thủ nghiêm ngặt của IEEE. Vì lý do này, rất ít ngôn ngữ lập trình đảm bảo tuân thủ nghiêm ngặt của IEEE.


7
Một bộ phần cứng "kỳ lạ" khác là các máy tính lớn của IBM trong đó định dạng dấu phẩy động có trước tiêu chuẩn IEEE. Không giống như Java, C ++ vẫn có thể sử dụng phần cứng hiện có.
Bo Persson

5
IEEE 754 không được GPU hỗ trợ đầy đủ.
kerem

3
Việc thiếu tuân thủ nghiêm ngặt đối với IEEE 754 là một vấn đề khiến một số người lo lắng, nhưng tôi không nghĩ là nó nằm trong phạm vi của các vấn đề mà OP thực sự quan tâm.
Omnifarious

3
@Matthieu Vì đây cũng được gắn thẻ "C", tôi nên đề cập đến một bộ phân tích C có thể cho bạn biết tất cả các giá trị mà chương trình dấu phẩy động của bạn có thể có với các thanh ghi dấu phẩy động 80 bit được đổ vào bộ nhớ tại bộ biên dịch C. blog.frama-c.com/index.php?post/2011/03/03/cosine-for-real
Pascal Cuoq

2
@MatthieuM.: ISO / ANSI quá tệ đã không cho phép các tham số biến đổi chỉ định kích thước tối thiểu / cực đại cho các đối số dấu phẩy động và số nguyên; nếu họ có, 80 bit long doublecó thể là một loại hữu ích và tồn tại lâu dài, vì một vấn đề thực sự với nó là nó hoạt động rất tệ printf. Thực tế là bộ đôi mở rộng lưu trữ số 1 dẫn đầu tăng tốc rõ ràng các tính toán trên các hệ thống không phải của FPU và cũng sẽ loại bỏ sự cần thiết phải xử lý các biến thể đặc biệt trong bất kỳ bối cảnh nào khác ngoài chuyển đổi sang / từ các loại khác. Quá tệ C đã printflàm mọi thứ rối tung lên.
supercat

40

Tôi tìm thấy liên kết này liệt kê một số hệ thống trong đó CHAR_BIT != 8. Chúng bao gồm

một số DSP DSP có CHAR_BIT == 16

Chip BlueCore-5 (chip Bluetooth của Cambridge Silicon Radio) có CHAR_BIT == 16.

Và tất nhiên, có một câu hỏi về Stack Overflow: Nền tảng nào có thứ gì khác ngoài char 8 bit

Đối với các hệ thống bổ sung không có hai, có một cách đọc thú vị trên comp.lang.c ++. Được kiểm duyệt . Tóm tắt: có những nền tảng có đại diện bổ sung hoặc ký hiệu và cường độ.


5
Các thiết bị tương tự DSP SHARC 32 bit có CHAR_BIT=32, và DSP của Texas từ TMS32F28xx có CHAR_BIT=16. GCC 3.2 cho PDP-10 có CHAR_BIT=9. Tôi nghĩ, S / 360 cũng có thể có char không 8 bit.
osgx

1
Tôi vẫn muốn có một ví dụ cho kiến ​​trúc 'không hai bổ sung'. Đặc biệt là vì nó đã xảy ra rằng CHAR_BITSmột bản sao một phần.
Yakov Galka

Các DSP TI chỉ có các ký tự 16 bit vì những người triển khai đã chọn nó (sẽ cần thêm một chút công việc để làm cho nó hoạt động tốt, nhưng IIRC không khó một cách vô lý - có lẽ chỉ là một số "lỗ hổng" trong giàn giáo codegen trong trình biên dịch cơ bản) . Vì vậy, nó không phải là một lý do kiến ​​trúc sâu sắc. Mã C hoạt động trên một máy trừu tượng. Nếu tất cả những gì bạn có là INT 16 bit, hãy lưu trữ hai ký tự trong mỗi ký tự và thêm sáp nhập đọc-sửa đổi-ghi vào trình tối ưu hóa lổ nhìn trộm (ít nhất là). Chắc chắn, đó là công việc nhiều hơn, nhưng chỉ cần nhìn vào bao nhiêu công việc cho mọi người để đối phó với các loại kỳ lạ như vậy ở những nơi mà họ sẽ không bao giờ xuất hiện. Kinh quá.
Phục hồi

24

Tôi khá chắc chắn rằng các hệ thống VAX vẫn đang được sử dụng. Họ không hỗ trợ điểm nổi của IEEE; họ sử dụng định dạng riêng của họ. Alpha hỗ trợ cả định dạng dấu phẩy động VAX và IEEE.

Các máy vectơ Cray, như T90, cũng có định dạng dấu phẩy động riêng, mặc dù các hệ thống Cray mới hơn sử dụng IEEE. (T90 tôi đã sử dụng đã ngừng hoạt động vài năm trước; tôi không biết liệu có còn sử dụng hoạt động không.)

T90 cũng đã có / có một số đại diện thú vị cho con trỏ và số nguyên. Một địa chỉ gốc chỉ có thể trỏ đến một từ 64 bit. Trình biên dịch C và C ++ có CHAR_BIT == 8 (cần thiết vì nó chạy Unicos, một hương vị của Unix và phải tương tác với các hệ thống khác), nhưng một địa chỉ gốc chỉ có thể trỏ đến một từ 64 bit. Tất cả các hoạt động ở mức byte được trình biên dịch tổng hợp và a void*hoặc char*lưu trữ một byte bù theo 3 bit thứ tự cao của từ. Và tôi nghĩ rằng một số loại số nguyên có bit đệm.

Máy tính lớn của IBM là một ví dụ khác.

Mặt khác, các hệ thống cụ thể này không nhất thiết phải loại trừ các thay đổi đối với tiêu chuẩn ngôn ngữ. Cray không cho thấy bất kỳ mối quan tâm đặc biệt nào trong việc nâng cấp trình biên dịch C của nó lên C99; có lẽ điều tương tự được áp dụng cho trình biên dịch C ++. Có thể hợp lý để thắt chặt các yêu cầu đối với việc triển khai được lưu trữ, chẳng hạn như yêu cầu CHAR_BIT == 8, dấu phẩy động định dạng IEEE nếu không phải là ngữ nghĩa đầy đủ và bổ sung 2 mà không cần bit đệm cho số nguyên đã ký. Các hệ thống cũ có thể tiếp tục hỗ trợ các tiêu chuẩn ngôn ngữ trước đó (C90 không chết khi C99 xuất hiện) và các yêu cầu có thể lỏng lẻo hơn đối với việc triển khai tự do (hệ thống nhúng) như DSP.

Mặt khác, có thể có những lý do chính đáng để các hệ thống trong tương lai thực hiện những điều được coi là kỳ lạ ngày nay.


6
Điểm tốt ở cuối về cách các tiêu chuẩn quá nghiêm ngặt ngăn chặn sự đổi mới. Khi chúng ta có các máy tính lượng tử (hoặc hữu cơ) có trạng thái nhị phân, các yêu cầu số học modulo cho unsignedcác loại tích phân sẽ là một nỗi đau lớn, trong khi số học đã ký sẽ ổn.
Ben Voigt

@BenVoigt Tại sao mỹ phẩm không dấu đó là một nỗi đau? Không thể bổ sung modulo 3 ^ n trong các máy tính đó?
phuclv

2
@ LưuViênPhúc: Đó chính xác là vấn đề, với các hoạt động phần cứng được thực hiện modulo 3 ** n, việc cung cấp các loại không dấu C ++ có hoạt động được xác định modulo 2 ** n sẽ khó khăn.
Ben Voigt

2
Tôi biết một VAX 11/780 vẫn được sử dụng làm máy chủ lưu trữ cho trình biên dịch chéo nhắm vào một hệ thống nhúng chuyên dụng có kiến ​​trúc độc quyền. Để duy trì VAX cụ thể đó, những người giám sát đã tiếp cận các viện bảo tàng cho các phụ tùng.
Peter

2
@Keith - về mặt kỹ thuật, trở ngại duy nhất là trải qua một quá trình để cung cấp bằng chứng sẽ đáp ứng các yêu cầu quy định, vì hệ thống nhúng mục tiêu có mức độ quan trọng cao. Có một loạt các trở ngại phi kỹ thuật (chính trị tổ chức, v.v.), tuy nhiên, cho đến nay vẫn không thể vượt qua. Hiện tại, việc gắn một trường hợp để đột kích các bảo tàng dễ dàng hơn là cập nhật máy chủ.
Peter

16

CHAR_BITS

Theo mã nguồn gcc :

CHAR_BIT16bit cho 1750a , dsp16xx kiến trúc.
CHAR_BIT24bit cho kiến trúc dsp56k .
CHAR_BIT32bit cho kiến trúc c4x .

Bạn có thể dễ dàng tìm thấy nhiều hơn bằng cách làm:

find $GCC_SOURCE_TREE -type f | xargs grep "#define CHAR_TYPE_SIZE"

hoặc là

find $GCC_SOURCE_TREE -type f | xargs grep "#define BITS_PER_UNIT"

nếu CHAR_TYPE_SIZEđược xác định một cách thích hợp.

Tuân thủ IEEE 754

Nếu kiến ​​trúc đích không hỗ trợ các hướng dẫn dấu phẩy động, gcc có thể tạo phù thủy dự phòng phần mềm không theo tiêu chuẩn theo mặc định. Hơn nữa, các tùy chọn đặc biệt (như -funsafe-math-optimizationsphù thủy cũng vô hiệu hóa việc bảo quản dấu hiệu cho số không) có thể được sử dụng.


3
nâng cấp chỉ đơn giản là chỉ đạo OP xem xét nguồn của trình biên dịch phổ biến; đây là định nghĩa của RFTM trong trường hợp này, vì vậy nó phải là nơi đầu tiên mọi người nhìn vào.
gạch

9

Đại diện nhị phân của IEEE 754 là không phổ biến trên GPU cho đến gần đây, xem Paranoia nổi điểm GPU .

EDIT: một câu hỏi đã được đặt ra trong các ý kiến ​​cho dù điểm nổi GPU có liên quan đến chương trình máy tính thông thường, không liên quan đến đồ họa hay không. Chết tiệt Hầu hết mọi thứ hiệu suất cao được tính toán công nghiệp ngày nay đều được thực hiện trên GPU; danh sách này bao gồm AI, khai thác dữ liệu, mạng lưới thần kinh, mô phỏng vật lý, dự báo thời tiết và nhiều hơn nữa. Một trong những liên kết trong các ý kiến ​​cho thấy lý do tại sao: một thứ tự lợi thế điểm nổi lớn của GPU.

Một điều nữa tôi muốn thêm vào, có liên quan nhiều hơn đến câu hỏi OP: mọi người đã làm gì cách đây 10 - 15 năm khi điểm nổi GPU không phải là IEEE và khi không có API như OpenCL hay CUDA ngày nay để lập trình GPU? Dù bạn có tin hay không, những người tiên phong về điện toán GPU đã quản lý để lập trình GPU mà không cần API để làm điều đó ! Tôi đã gặp một trong số họ trong công ty của tôi. Đây là những gì anh ta đã làm: anh ta mã hóa dữ liệu anh ta cần để tính toán như một hình ảnh với các pixel đại diện cho các giá trị anh ta đang làm việc, sau đó sử dụng OpenGL để thực hiện các thao tác anh ta cần (chẳng hạn như "gaussian Blur" để biểu thị một tích chập với phân phối bình thường , v.v.) và giải mã hình ảnh kết quả thành một mảng kết quả. Và điều này vẫn nhanh hơn so với sử dụng CPU!

Những thứ như vậy là điều đã thúc đẩy NVidia cuối cùng làm cho dữ liệu nhị phân nội bộ của họ tương thích với IEEE và giới thiệu API theo định hướng tính toán thay vì thao tác hình ảnh.


GPU có liên quan như thế nào? (a) Trang này có vẻ rất lỗi thời. (b) Cho đến ngày hôm nay, bạn không thể lập trình GPU trong C: bởi vì C hỗ trợ những thứ như chức năng đệ quy mà GPU, theo hiểu biết tốt nhất của tôi, thì không. Vì vậy, bạn thậm chí không thể viết một trình biên dịch nếu bạn muốn.
Yakov Galka

1
@ybungalobill, giảm tải công việc lặp đi lặp lại cho GPU hiện phương pháp ưa thích cho các tính toán quy mô lớn . Trong thực tế, tôi hiện đang phát triển một trong C ++. May mắn thay, chúng tôi chỉ làm việc với các GPU NVDA CUDA có biểu diễn nhị phân tương thích với chuẩn IEEE 754.
Michael

Tôi không nói GPU không được sử dụng cho tính toán GP. Tôi đã nói rằng bạn không thực sự lập trình các hạt nhân trong C, mặc dù có sự giống nhau về cú pháp. Bạn có thể thực thi int f(int n) { return n <= 1 ? 1 : n * f(n-1); }trong CUDA không? Nếu không thì GPU không liên quan đến câu hỏi này (câu hỏi về ủy ban C và C ++).
Yakov Galka

6
@ybungalobill: một số câu trả lời cho điều đó. Đầu tiên, CUDA không hỗ trợ C, C ++ và Fortran . Xem cùng một liên kết để biết lợi thế về hiệu suất cực lớn của GPU 2048 luồng so với CPU 8 luồng thông thường của bạn. Thứ hai, đúng, chỉ các tập hợp con (mặc dù các ngôn ngữ lớn) của các ngôn ngữ đó được hỗ trợ, bao gồm thiếu hỗ trợ cho phép đệ quy mô hình lập trình CUDA (gọi là "song song động") cho đến CUDA 5.0. Thứ ba, thu hồi thường có thể được thay thế bằng các vòng lặp, điều này cần thiết cho sự hoàn hảo đa luồng.
Michael
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.