Tiêu chuẩn C ++ cho biết kích thước của int, loại dài là gì?


696

Tôi đang tìm kiếm thông tin chi tiết về kích thước của các loại C ++ cơ bản. Tôi biết rằng nó phụ thuộc vào kiến ​​trúc (16 bit, 32 bit, 64 bit) và trình biên dịch.

Nhưng có tiêu chuẩn nào cho C ++ không?

Tôi đang sử dụng Visual Studio 2008 trên kiến ​​trúc 32 bit. Đây là những gì tôi nhận được:

char  : 1 byte
short : 2 bytes
int   : 4 bytes
long  : 4 bytes
float : 4 bytes
double: 8 bytes

Tôi cố gắng để tìm kiếm, mà không có nhiều thành công, thông tin đáng tin cậy nêu rõ kích thước của char, short, int, long, double, float(và các loại khác mà tôi không nghĩ ra) theo kiến trúc và trình biên dịch khác nhau.


18
@thyrgle không phải do lựa chọn ... có rất nhiều kiến ​​trúc để hỗ trợ mà nó cần phải linh hoạt.
Krakkos


4
Tại sao họ không xóa tất cả các loại mơ hồ và chuẩn hóa tất cả các loại có độ dài bit xác định, ví dụ: int32_t, uint32_t, int64_t, v.v.
developerbmw

5
@thyrgle Thực sự khá khó khăn để chuẩn hóa một cái gì đó như thế này. Không giống như Java, nơi những thứ này không đổi do cách thức hoạt động của JVM, C / C ++ về cơ bản phải bám vào hệ thống mà chúng được chạy trên mà không có bất kỳ lớp trừu tượng ưa thích nào (ít nhất là không nhiều như với Java) trong- giữa. Nếu kích thước của int là quan trọng mà người ta có thể sử dụng int16_t, int32_tint64_t(cần iostreambao gồm cho điều đó nếu tôi nhớ chính xác). Điều tuyệt vời ở đây là int64_t không nên có vấn đề trên hệ thống 32 bit (điều này sẽ ảnh hưởng đến hiệu suất).
rbaleksandar

5
@rbaleksandar Họ thực sự được định nghĩa trong <cstdint>, không <iostream>.
Thời gian của Justin - Tái lập lại

Câu trả lời:


685

Tiêu chuẩn C ++ không chỉ định kích thước của các loại tích phân theo byte, nhưng nó chỉ định các phạm vi tối thiểu mà chúng phải có khả năng giữ. Bạn có thể suy ra kích thước tối thiểu theo bit từ phạm vi yêu cầu. Bạn có thể suy ra kích thước tối thiểu theo byte từ đó và giá trị của CHAR_BITmacro xác định số lượng bit trong một byte . Trong tất cả các nền tảng khó hiểu nhất là 8 và không thể nhỏ hơn 8. Đó là vì nó phải đủ lớn để chứa "các đơn vị mã tám bit của mẫu mã hóa Unicode UTF-8".

Một ràng buộc bổ sung cho charlà kích thước của nó luôn là 1 byte hoặc CHAR_BITbit (do đó là tên). Điều này được nêu rõ ràng trong tiêu chuẩn.

Tiêu chuẩn C là một tham chiếu chuẩn cho tiêu chuẩn C ++, do đó, mặc dù nó không nêu rõ các yêu cầu này, C ++ yêu cầu các phạm vi tối thiểu theo tiêu chuẩn C (trang 22), giống như các phạm vi từ Phạm vi loại dữ liệu trên MSDN :

  1. signed char: -127 đến 127 (lưu ý, không phải từ -128 đến 127; điều này phù hợp với các nền tảng bổ sung và ký hiệu của 1)
  2. unsigned char: 0 đến 255
  3. "plain" char: cùng phạm vi với signed charhoặc unsigned char, được xác định theo triển khai
  4. signed short: -32767 đến 32767
  5. unsigned short: 0 đến 65535
  6. signed int: -32767 đến 32767
  7. unsigned int: 0 đến 65535
  8. signed long: -2147483647 đến 2147483647
  9. unsigned long: 0 đến 4294967295
  10. signed long long: -9223372036854775807 đến 9223372036854775807
  11. unsigned long long: 0 đến 18446744073709551615

Việc triển khai C ++ (hoặc C) có thể xác định kích thước của một loại theo byte sizeof(type)cho bất kỳ giá trị nào, miễn là

  1. biểu thức sizeof(type) * CHAR_BITước tính một số bit đủ cao để chứa các phạm vi cần thiết và
  2. thứ tự của loại vẫn còn hiệu lực (ví dụ sizeof(int) <= sizeof(long)).

Đặt tất cả những thứ này lại với nhau, chúng tôi đảm bảo rằng:

  • char, signed charunsigned charcó ít nhất 8 bit
  • signed short, unsigned short, signed int, Và unsigned intít nhất 16 bit
  • signed longunsigned longcó ít nhất 32 bit
  • signed long longunsigned long longcó ít nhất 64 bit

Không có đảm bảo nào được thực hiện về kích thước floathoặc doublengoại trừ doublecung cấp ít nhất độ chính xác như float.

Các phạm vi cụ thể triển khai thực tế có thể được tìm thấy trong <limits.h>tiêu đề trong C hoặc <climits>trong C ++ (hoặc thậm chí tốt hơn, được đặt std::numeric_limitstrong <limits>tiêu đề).

Ví dụ: đây là cách bạn sẽ tìm thấy phạm vi tối đa cho int:

C:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C ++ :

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();

49
Thay vào đó, tiêu chuẩn C ++ sử dụng byte từ có nghĩa là "1 char" chứ không phải nghĩa thông thường.
Ben Voigt

4
@Programmer Đọc câu trả lời (ghi chú điểm 1 trong ngoặc đơn) hoặc từ ngữ của tiêu chuẩn thực tế (được liên kết trong câu trả lời). Tiêu chuẩn C chứa các kiến ​​trúc bổ sung của 1, có đại diện khác với phần bổ sung 2 phổ biến nhất. Phạm vi được đảm bảo tối thiểu sẽ luôn luôn khác với phạm vi thực tế mà việc triển khai cung cấp.
Alex B

9
@Alex B bạn đã không đề cập bất cứ điều gì về gấp đôi trong câu trả lời của bạn. Bạn có thể vui lòng cập nhật câu trả lời của bạn cho các biến số dấu phẩy động?
Cool_Coder

3
@Cool_Coder: Điểm nổi là toàn bộ ấm cá bổ sung, dễ dàng nhân đôi kích thước bài viết.
Ded repeatator

3
@Mooing Duck: "tất cả các phiên bản của C ++ yêu cầu 256 giá trị riêng biệt [đối với các loại char đã ký]" Không, điều đó không đúng cho đến khi nó được sửa trong các thông số kỹ thuật C ++ gần đây hơn. Các thông số kỹ thuật cũ hơn cho phép các kiểu char đã ký có các mẫu bit không ánh xạ tới một số, vì vậy chúng bị thiếu yêu cầu phải có 256 giá trị riêng biệt. "Đối với các loại ký tự không dấu, tất cả các mẫu bit có thể có của biểu diễn giá trị đại diện cho các số. Các yêu cầu này không giữ cho các loại khác."
Adrian McCarthy

241

Đối với các hệ thống 32 bit, tiêu chuẩn 'thực tế' là ILP32 - nghĩa là int, longvà con trỏ đều là các đại lượng 32 bit.

Đối với các hệ thống 64 bit, tiêu chuẩn 'thực tế' của Unix là LP64 - longvà con trỏ là 64 bit (nhưng intlà 32 bit). Windows 64-bit giữa các ý kiến LLP64 - long longvà con trỏ là 64-bit (nhưng longintcả hai đều 32-bit).

Tại một thời điểm, một số hệ thống Unix đã sử dụng một tổ chức ILP64.

Không có tiêu chuẩn thực tế nào trong số này được quy định theo tiêu chuẩn C (ISO / IEC 9899: 1999), nhưng tất cả đều được nó cho phép.

Và, theo định nghĩa, sizeof(char)1, mặc dù thử nghiệm trong tập lệnh cấu hình Perl.

Lưu ý rằng có các máy (Crays) CHAR_BITlớn hơn 8. Điều đó có nghĩa là IIRC, sizeof(int)cũng là 1, vì cả hai charintđều là 32 bit.


73
+1 để nêu rõ mọi thứ thực sự như thế nào trong các trường hợp quan trọng nhất, hơn là cách mọi thứ trong lý thuyết. Nếu bạn muốn 32bit sử dụng int, nếu bạn muốn 64bit sử dụng lâu dài. Nếu bạn muốn sử dụng size_t. Tránh "đơn giản" lâu vì nó thay đổi. Điều đó sẽ làm việc cho hầu hết các ứng dụng.
Eloff

37
+1 cho câu trả lời. @Eloff: ngược lại ... nếu bạn muốn sử dụng 32 bit [u]int32_thoặc tương tự, nếu bạn muốn sử dụng 64 bit [u]int64_t... nếu bạn không có tiêu đề cho chúng, hãy tải xuống hoặc tạo một cái, tốt nhất là chọn thời gian biên dịch các loại hoặc xác nhận tĩnh để xác minh kích thước. pubs.opengroup.org/onlinepub/009695299/basingefs/stdint.h.html Nếu kích thước chính xác không quá quan trọng và bạn chỉ quan tâm đến chúng ít nhất là lớn, thì lời khuyên của bạn dành cho các nền tảng máy chủ / PC hiện đại phổ biến.
Tony Delroy

8
Lưu ý rằng không chỉ các máy cray cũ có CHAR_BIT> 8. ví dụ: DSP thường có CHAR_BIT là 16 hoặc 32. (xem ví dụ: các máy này )
nos

2
@nos: Cảm ơn bạn đã liên kết. Nó rất hữu ích để có các hệ thống hiện đại, hiện đại được xác định cho các trường hợp lẻ bóng. Vì tò mò, mã được đặt trên các máy đó là gì? Nếu bộ mã là UTF-16, thì 0xFFFF không phải là ký tự hợp lệ và nếu bộ mã là bộ mã ISO 8859-x, thì 0xFFFF lại không phải là ký tự hợp lệ (mã ký tự từ 0x00 đến 0xFF là hợp lệ). Tôi chưa tin rằng có một vấn đề phát hiện EOF, nhưng chắc chắn có sự thận trọng, và có lẽ là để viết và sử dụng một hàm int get_char(FILE *fp, char *c)trả về EOF hoặc 0 và thiết lập *c.
Jonathan Leffler

2
@joelw: C11 yêu cầu rằng, uint32_t x=1,y=2;với giá trị x-yphải là 4294967295 trên các nền tảng trong đó "int" là 32 bit hoặc nhỏ hơn và -1 trên các nền tảng trong đó "int" là 33 bit hoặc lớn hơn. Hơn nữa, nó yêu cầu x*yphải được đánh giá bằng cách sử dụng số học mô-đun cho tất cả các giá trị của x và y nếu "int" là 32 bit hoặc nhỏ hơn và số học thông thường nếu 65 bit hoặc lớn hơn, nhưng không đặt bất kỳ yêu cầu nào về những gì có thể xảy ra với giá trị lớn của x và y nếu "int" là 33 đến 64 bit.
supercat

88

Trong thực tế không có điều đó. Thường thì bạn có thể mong đợi std::size_tđại diện cho kích thước nguyên gốc không dấu trên kiến ​​trúc hiện tại. tức là 16 bit, 32 bit hoặc 64 bit nhưng không phải lúc nào cũng như trường hợp được nêu trong các bình luận cho câu trả lời này.

Theo như tất cả các loại tích hợp khác, nó thực sự phụ thuộc vào trình biên dịch. Dưới đây là hai trích đoạn được lấy từ bản thảo làm việc hiện tại của tiêu chuẩn C ++ mới nhất:

Có năm loại số nguyên được ký tiêu chuẩn: ký char, short int, int, long int và long long int. Trong danh sách này, mỗi loại cung cấp ít nhất dung lượng lưu trữ như những loại trước nó trong danh sách.

Đối với mỗi loại số nguyên được ký tiêu chuẩn, tồn tại một loại số nguyên không dấu tiêu chuẩn tương ứng (nhưng khác nhau): unsign char, unsign short int, unsign int, unsign long int và unsign long int, mỗi loại chiếm cùng một lượng lưu trữ và có cùng yêu cầu căn chỉnh.

Nếu bạn muốn, bạn có thể tĩnh (thời gian biên dịch) xác nhận kích thước của các loại cơ bản này. Nó sẽ cảnh báo mọi người suy nghĩ về việc chuyển mã của bạn nếu các giả định sizeof thay đổi.


7
bài tốt. một điều nữa được yêu cầu là kích thước bit nhỏ nhất sau đây (được ghi trong c89 / c99 cùng với giới hạn.h và được đảm nhận bởi c ++): char> = 8, short và int> = 16, long> = 32.
Julian Schaub - litb

1
Ngoài ra, trên nền tảng AVR 8 bit size_t sẽ không phải là 8 bit, mà là 16, vì kích thước con trỏ và int là 16 bit. Vì vậy, kích thước dữ liệu riêng của bộ xử lý không liên quan đến size_t.
Robotbugs

80

Có tiêu chuẩn.

Tiêu chuẩn C90 yêu cầu rằng

sizeof(short) <= sizeof(int) <= sizeof(long)

Tiêu chuẩn C99 yêu cầu rằng

sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

Dưới đây là thông số kỹ thuật của C99 . Trang 22 chi tiết kích thước của các loại tích phân khác nhau.

Dưới đây là kích thước kiểu int (bit) cho nền tảng Windows:

Type           C99 Minimum     Windows 32bit
char           8               8
short          16              16
int            16              32
long           32              32
long long      64              64

Nếu bạn quan tâm đến tính di động hoặc bạn muốn tên của loại phản ánh kích thước, bạn có thể xem tiêu đề <inttypes.h>, nơi có các macro sau:

int8_t
int16_t
int32_t
int64_t

int8_tđược đảm bảo là 8 bit, và int16_tđược đảm bảo là 16 bit, v.v.


8
Tiêu chuẩn nhỏ: tiêu chuẩn nói ở đâu sizeof(long) < sizeof(long long)trái ngược với đối xứng sizeof(long) <= sizeof(long long)?
Jonathan Leffler

2
@JonathonLeffler - xem C99 5.2.4.2.1 - Kích thước của các loại số nguyên. hqizeof (int) == 16-bit, hqizeof (dài) == 32-bit, hqizeof (dài dài) == 64-bit. Vì vậy, tôi nghĩ rằng bạn đã đúng về <= vì không có maxsizeof (loại) được chỉ định.
Jesse Chisholm

Tương tự sizeof (float) <= sizeof (double) <= sizeof (long double). Theo C99 7.12 đoạn 2.
Jesse Chisholm

38

Nếu bạn cần các loại kích thước cố định, hãy sử dụng các loại như uint32_t (số nguyên không dấu 32 bit) được xác định trong stdint.h . Chúng được quy định trong C99 .


10
Chúng được chỉ định nhưng không bắt buộc.
dreamlax

2
@dreamlax Những nền tảng nào không bao gồm nó?
Levi Morrison

3
@LeviMorrison: Bất kỳ nền tảng nào không có chúng ở dạng bắt buộc. Một nền tảng CHAR_BIT == 16, ví dụ, sẽ không có int8_t. Bất kỳ nền tảng nào không sử dụng phần bù hai sẽ không có bất kỳ phần nào trong số chúng (vì phần bổ sung của hai được yêu cầu theo tiêu chuẩn).
DevSolar

36

Đã cập nhật: C ++ 11 đưa các loại từ TR1 chính thức vào tiêu chuẩn:

  • dài dài int
  • không dấu dài dài int

Và các loại "cỡ" từ <cstdint>

  • int8_t
  • int16_t
  • int32_t
  • int64_t
  • (và các đối tác không dấu).

Thêm vào đó bạn nhận được:

  • int_least8_t
  • int_least16_t
  • int_least32_t
  • int_least64_t
  • Cộng với các đối tác không dấu.

Các loại này đại diện cho các loại số nguyên nhỏ nhất với ít nhất số bit được chỉ định. Tương tự, có các loại số nguyên "nhanh nhất" với ít nhất số bit được chỉ định:

  • int_fast8_t
  • int_fast16_t
  • int_fast32_t
  • int_fast64_t
  • Cộng với các phiên bản không dấu.

"Nhanh" nghĩa là gì, nếu có bất cứ điều gì, tùy thuộc vào việc thực hiện. Nó không cần phải là nhanh nhất cho tất cả các mục đích.


Đây là một phần của tiêu chuẩn C ++ 11 bây giờ.
Jaan

2
"nhanh" chỉ có nghĩa là phù hợp với kiến ​​trúc phần cứng. Nếu các thanh ghi là 16 bit, thì int_fast8_t là giá trị 16 bit. Nếu các thanh ghi là 32 bit, thì int_fast8_t và int_fast16_t đều là các giá trị 32 bit. v.v ... Xem phần C99 7.18.1.3 đoạn 2.
Jesse Chisholm

19

Các ++ Chuẩn C nói nó như thế này:

3.9.1, §2:

Có năm loại số nguyên đã ký: "char char", "short int", "int", "long int" và "long long int". Trong danh sách này, mỗi loại cung cấp ít nhất dung lượng lưu trữ như những loại trước nó trong danh sách. Ints int có kích thước tự nhiên được đề xuất bởi kiến ​​trúc của môi trường thực thi (44); các loại số nguyên đã ký khác được cung cấp để đáp ứng nhu cầu đặc biệt.

(44) nghĩa là đủ lớn để chứa bất kỳ giá trị nào trong phạm vi INT_MIN và INT_MAX, như được định nghĩa trong tiêu đề <climits> .

Kết luận: Nó phụ thuộc vào kiến ​​trúc mà bạn đang làm việc. Bất kỳ giả định nào khác là sai.


12

Không, không có tiêu chuẩn cho kích thước loại. Tiêu chuẩn chỉ yêu cầu:

sizeof(short int) <= sizeof(int) <= sizeof(long int)

Điều tốt nhất bạn có thể làm nếu bạn muốn các biến có kích thước cố định là sử dụng các macro như thế này:

#ifdef SYSTEM_X
  #define WORD int
#else
  #define WORD long int
#endif

Sau đó, bạn có thể sử dụng WORD để xác định các biến của mình. Không phải tôi thích điều này mà là cách dễ mang theo nhất.


4
Vấn đề là WORD bị lây lan xung quanh chương trình vào các khu vực không thực sự phụ thuộc vào kích thước cố định (xem một số mã cửa sổ). Như tôi đã tìm ra khi chuyển từ hệ thống 16 bit sang 32 bit, bạn sẽ gặp phải cùng một vấn đề mà WORD muốn giải quyết.
lilburne

@liburne Tất nhiên bạn chỉ nên sử dụng WORD khi bạn cần một biến có kích thước cố định, như khi bạn đang đọc / ghi từ / vào một tệp. Nếu một đoạn mã không thực sự phụ thuộc vào kích thước cố định, thì bạn nên sử dụng các biến "int" bình thường.
Emiliano

3
Điều tốt nhất bạn có thể làm để có được kích thước di động nên là#include <boost/cstdint.hpp>
kizzx2

11

Chúng tôi được phép xác định một từ đồng nghĩa cho loại để chúng tôi có thể tạo "tiêu chuẩn" của riêng mình.

Trên một máy trong đó sizeof (int) == 4, chúng ta có thể xác định:

typedef int int32;

int32 i;
int32 j;
...

Vì vậy, khi chúng ta chuyển mã sang một máy khác trong đó thực tế kích thước của int dài là 4, chúng ta chỉ có thể xác định lại sự xuất hiện duy nhất của int.

typedef long int int32;

int32 i;
int32 j;
...

1
Điều đó không cần thiết cho tiêu đề tiêu chuẩn <stdint.h>(C99 trở lên và bất kỳ tiêu chuẩn C ++ nào áp dụng phiên bản C99 của thư viện C).
Keith Thompson

8

Đối với số dấu phẩy động có một tiêu chuẩn (IEEE754) : số float là 32 bit và nhân đôi là 64. Đây là tiêu chuẩn phần cứng, không phải là tiêu chuẩn C ++, vì vậy về mặt lý thuyết, các trình biên dịch có thể định nghĩa float và nhân đôi với một số kích thước khác, nhưng trong thực tế tôi ' chưa bao giờ thấy một kiến ​​trúc sử dụng bất cứ điều gì khác nhau.


2
Tuy nhiên, việc tuân thủ với IEEE 754 (còn gọi là IEC 559) là tùy chọn trong C ++ (có thể là C, nhưng tôi không chắc chắn). Xem std :: num_limits :: is_iec559.
Hội trường Drew

1
Sau đó, bạn chưa thấy trình biên dịch của TI cho DSP TMS320C28xx, nơi doublecó cùng kích thước float(và intgiống như char, cả hai đều là 16 bit). Nhưng họ có 64 bit long double.
starblue

7

Có một tiêu chuẩn và nó được quy định trong các tài liệu tiêu chuẩn khác nhau (ISO, ANSI và whatnot).

Wikipedia có một trang tuyệt vời giải thích các loại khác nhau và tối đa họ có thể lưu trữ: Integer trong Khoa học máy tính.

Tuy nhiên, ngay cả với trình biên dịch C ++ tiêu chuẩn, bạn có thể tìm thấy tương đối dễ dàng bằng cách sử dụng đoạn mã sau:

#include <iostream>
#include <limits>


int main() {
    // Change the template parameter to the various different types.
    std::cout << std::numeric_limits<int>::max() << std::endl;
}

Tài liệu cho std :: num_limits có thể được tìm thấy tại Roguewave . Nó bao gồm rất nhiều lệnh khác mà bạn có thể gọi để tìm hiểu các giới hạn khác nhau. Điều này có thể được sử dụng với bất kỳ loại tùy ý nào truyền tải kích thước, ví dụ std :: streamize.

Câu trả lời của John chứa mô tả tốt nhất, vì những điều đó được đảm bảo để giữ. Bất kể bạn đang ở trên nền tảng nào, có một trang tốt khác đi sâu vào chi tiết hơn về mỗi loại PHẢI chứa bao nhiêu bit: loại int , được xác định trong tiêu chuẩn.

Tôi hi vọng cái này giúp được!



7

Bạn có thể dùng:

cout << "size of datatype = " << sizeof(datatype) << endl;

datatype = int, long intv.v. Bạn sẽ có thể thấy kích thước cho bất kỳ kiểu dữ liệu nào bạn nhập.


7

Khi nói đến các kiểu được xây dựng cho các kiến ​​trúc khác nhau và các trình biên dịch khác nhau, chỉ cần chạy đoạn mã sau trên kiến ​​trúc của bạn với trình biên dịch của bạn để xem nó xuất ra cái gì. Dưới đây cho thấy đầu ra Ubuntu 13.04 (Rared Ringtail) 64 bit g ++ 4.7.3 của tôi. Ngoài ra, vui lòng lưu ý những gì đã được trả lời dưới đây, đó là lý do tại sao đầu ra được đặt hàng như vậy:

"Có năm loại số nguyên được ký tiêu chuẩn: ký char, short int, int, long int và long long int. Trong danh sách này, mỗi loại cung cấp ít nhất nhiều dung lượng lưu trữ như các loại trước nó trong danh sách."

#include <iostream>

int main ( int argc, char * argv[] )
{
  std::cout<< "size of char: " << sizeof (char) << std::endl;
  std::cout<< "size of short: " << sizeof (short) << std::endl;
  std::cout<< "size of int: " << sizeof (int) << std::endl;
  std::cout<< "size of long: " << sizeof (long) << std::endl;
  std::cout<< "size of long long: " << sizeof (long long) << std::endl;

  std::cout<< "size of float: " << sizeof (float) << std::endl;
  std::cout<< "size of double: " << sizeof (double) << std::endl;

  std::cout<< "size of pointer: " << sizeof (int *) << std::endl;
}


size of char: 1
size of short: 2
size of int: 4
size of long: 8
size of long long: 8
size of float: 4
size of double: 8
size of pointer: 8

sizeof(char)không nên được bao gồm.
Ven

3

Như đã đề cập kích thước nên phản ánh kiến ​​trúc hiện tại. Bạn có thể lấy một đỉnh xung quanh limits.hnếu bạn muốn xem trình biên dịch hiện tại của bạn đang xử lý mọi thứ như thế nào.


Cảm ơn, nhưng tôi muốn biết kích thước cho các kiến ​​trúc tôi không có myselft (như 64 bit). Hướng dẫn này chỉ nói về kiến ​​trúc 32 bit ...
Jérôme

2

Như những người khác đã trả lời, tất cả các "tiêu chuẩn" đều để lại hầu hết các chi tiết là "triển khai được xác định" và chỉ nêu rõ loại "char" nằm ở mức rộng "char_bis" và "char <= short <= int <= long < = long long "(float và double khá phù hợp với các tiêu chuẩn của dấu phẩy động của IEEE và double double thường giống như double - nhưng có thể lớn hơn đối với các triển khai hiện tại hơn).

Một phần lý do không có giá trị chính xác và cụ thể là do các ngôn ngữ như C / C ++ được thiết kế để có thể di chuyển tới một số lượng lớn nền tảng phần cứng - Bao gồm các hệ thống máy tính có kích thước từ "char" có thể là 4 bit hoặc 7 bit, hoặc thậm chí một số giá trị khác với máy tính "8- / 16- / 32- / 64-bit" mà người dùng máy tính gia đình trung bình tiếp xúc. (Kích thước từ ở đây có nghĩa là hệ thống thường hoạt động trên bao nhiêu bit - Một lần nữa, nó không phải lúc nào cũng là 8 bit như người dùng máy tính gia đình có thể mong đợi.)

Nếu bạn thực sự cần một đối tượng (theo nghĩa của một chuỗi bit đại diện cho một giá trị tích phân) của một số bit cụ thể, hầu hết các trình biên dịch có một số phương pháp chỉ định rằng; Nhưng nó thường không di động, ngay cả giữa các trình biên dịch được tạo bởi công ty ame nhưng cho các nền tảng khác nhau. Một số tiêu chuẩn và thực tiễn (đặc biệt là giới hạn. H và tương tự) đủ phổ biến để hầu hết các trình biên dịch sẽ hỗ trợ xác định loại phù hợp nhất cho một phạm vi giá trị cụ thể, nhưng không phải là số bit được sử dụng. (Nghĩa là, nếu bạn biết bạn cần giữ các giá trị trong khoảng từ 0 đến 127, bạn có thể xác định rằng trình biên dịch của bạn hỗ trợ loại 8 bit "int8" sẽ đủ lớn để giữ toàn bộ phạm vi mong muốn, nhưng không phải là một cái gì đó giống như loại "int7" sẽ khớp chính xác cho 7 bit.)

Lưu ý: Nhiều gói nguồn Un * x được sử dụng tập lệnh "./cool" sẽ thăm dò các khả năng của trình biên dịch / hệ thống và đưa ra một Makefile và config.h phù hợp. Bạn có thể kiểm tra một số các tập lệnh này để xem cách chúng hoạt động và cách chúng thăm dò các khả năng của trình biên dịch / hệ thống và làm theo sự dẫn dắt của chúng.


1

Nếu bạn quan tâm đến một giải pháp C ++ thuần túy, tôi đã sử dụng các mẫu và chỉ mã tiêu chuẩn C ++ để xác định các loại tại thời gian biên dịch dựa trên kích thước bit của chúng. Điều này làm cho các giải pháp di động trên các trình biên dịch.

Ý tưởng đằng sau rất đơn giản: Tạo một danh sách chứa các kiểu char, int, ngắn, dài, dài (phiên bản đã ký và không dấu) và quét danh sách và bằng cách sử dụng mẫu num_limits chọn loại có kích thước đã cho.

Bao gồm tiêu đề này, bạn có 8 loại stdtype :: int8, stdtype :: int16, stdtype :: int32, stdtype :: int64, stdtype :: uint8, stdtype :: uint16, stdtype :: uint32, stdtype :: uint.

Nếu một số loại không thể được biểu diễn, nó sẽ được ước tính thành stdtype :: null_type cũng được khai báo trong tiêu đề đó.

MÃ SỐ DƯỚI ĐÂY ĐƯỢC SỐNG KHÔNG CÓ BẢO HÀNH, VUI LÒNG KIỂM TRA NÓ.
TÔI MỚI Ở METAPROGRAMMING QUÁ, CẢM NHẬN MIỄN PHÍ CHỈNH SỬA VÀ ĐÚNG MÃ SỐ NÀY.
Đã thử nghiệm với DevC ++ (vì vậy phiên bản gcc khoảng 3.5)

#include <limits>

namespace stdtype
{
    using namespace std;


    /*
     * THIS IS THE CLASS USED TO SEMANTICALLY SPECIFY A NULL TYPE.
     * YOU CAN USE WHATEVER YOU WANT AND EVEN DRIVE A COMPILE ERROR IF IT IS 
     * DECLARED/USED.
     *
     * PLEASE NOTE that C++ std define sizeof of an empty class to be 1.
     */
    class null_type{};

    /*
     *  Template for creating lists of types
     *
     *  T is type to hold
     *  S is the next type_list<T,S> type
     *
     *  Example:
     *   Creating a list with type int and char: 
     *      typedef type_list<int, type_list<char> > test;
     *      test::value         //int
     *      test::next::value   //char
     */
    template <typename T, typename S> struct type_list
    {
        typedef T value;
        typedef S next;         

    };




    /*
     * Declaration of template struct for selecting a type from the list
     */
    template <typename list, int b, int ctl> struct select_type;


    /*
     * Find a type with specified "b" bit in list "list"
     *
     * 
     */
    template <typename list, int b> struct find_type
    {   
        private:
            //Handy name for the type at the head of the list
            typedef typename list::value cur_type;

            //Number of bits of the type at the head
            //CHANGE THIS (compile time) exp TO USE ANOTHER TYPE LEN COMPUTING
            enum {cur_type_bits = numeric_limits<cur_type>::digits};

        public:
            //Select the type at the head if b == cur_type_bits else
            //select_type call find_type with list::next
            typedef  typename select_type<list, b, cur_type_bits>::type type;
    };

    /*
     * This is the specialization for empty list, return the null_type
     * OVVERRIDE this struct to ADD CUSTOM BEHAVIOR for the TYPE NOT FOUND case
     * (ie search for type with 17 bits on common archs)
     */
    template <int b> struct find_type<null_type, b>
    {   
        typedef null_type type;

    };


    /*
     * Primary template for selecting the type at the head of the list if
     * it matches the requested bits (b == ctl)
     *
     * If b == ctl the partial specified templated is evaluated so here we have
     * b != ctl. We call find_type on the next element of the list
     */
    template <typename list, int b, int ctl> struct select_type
    {   
            typedef  typename find_type<typename list::next, b>::type type; 
    };

    /*
     * This partial specified templated is used to select top type of a list
     * it is called by find_type with the list of value (consumed at each call)
     * the bits requested (b) and the current type (top type) length in bits
     *
     * We specialice the b == ctl case
     */
    template <typename list, int b> struct select_type<list, b, b>
    {
            typedef typename list::value type;
    };


    /*
     * These are the types list, to avoid possible ambiguity (some weird archs)
     * we kept signed and unsigned separated
     */

    #define UNSIGNED_TYPES type_list<unsigned char,         \
        type_list<unsigned short,                           \
        type_list<unsigned int,                             \
        type_list<unsigned long,                            \
        type_list<unsigned long long, null_type> > > > >

    #define SIGNED_TYPES type_list<signed char,         \
        type_list<signed short,                         \
        type_list<signed int,                           \
        type_list<signed long,                          \
        type_list<signed long long, null_type> > > > >



    /*
     * These are acutally typedef used in programs.
     * 
     * Nomenclature is [u]intN where u if present means unsigned, N is the 
     * number of bits in the integer
     *
     * find_type is used simply by giving first a type_list then the number of 
     * bits to search for.
     *
     * NB. Each type in the type list must had specified the template 
     * numeric_limits as it is used to compute the type len in (binary) digit.
     */
    typedef find_type<UNSIGNED_TYPES, 8>::type  uint8;
    typedef find_type<UNSIGNED_TYPES, 16>::type uint16;
    typedef find_type<UNSIGNED_TYPES, 32>::type uint32;
    typedef find_type<UNSIGNED_TYPES, 64>::type uint64;

    typedef find_type<SIGNED_TYPES, 7>::type    int8;
    typedef find_type<SIGNED_TYPES, 15>::type   int16;
    typedef find_type<SIGNED_TYPES, 31>::type   int32;
    typedef find_type<SIGNED_TYPES, 63>::type   int64;

}

0
unsigned char bits = sizeof(X) << 3;

nơi Xlà một char, int, longvv .. sẽ cung cấp cho bạn kích thước của Xtheo bit.


1
một char không phải lúc nào cũng là 8 bit, vì vậy biểu thức của bạn sẽ không hoạt động trên các kiến trúc với char không 8 bit . Chỉ sizeof(type)*CHAR_BITgiữ
phuclv

Ngay cả khi CHAR_BITđược đảm bảo là 8 bit, << 3chỉ là một cách khó hiểu để viết * 8hoặc * CHAR_BIT.
Keith Thompson

0

Từ Alex B Tiêu chuẩn C ++ không chỉ định kích thước của các loại tích phân theo byte, nhưng nó chỉ định phạm vi tối thiểu mà chúng phải có khả năng giữ. Bạn có thể suy ra kích thước tối thiểu theo bit từ phạm vi yêu cầu. Bạn có thể suy ra kích thước tối thiểu tính theo byte từ đó và giá trị của macro CHAR_BIT xác định số lượng bit trong một byte (trong tất cả các nền tảng khó hiểu nhất là 8 và không thể nhỏ hơn 8).

Một ràng buộc bổ sung cho char là kích thước của nó luôn là 1 byte hoặc các bit CHAR_BIT (do đó là tên).

Phạm vi tối thiểu theo tiêu chuẩn (trang 22) là:

và Phạm vi loại dữ liệu trên MSDN:

đã ký char: -127 đến 127 (lưu ý, không phải -128 đến 127; điều này phù hợp với các nền tảng bổ sung của 1) không dấu char: 0 đến 255 "plain" char: -127 đến 127 hoặc 0 đến 255 (tùy thuộc vào ký char mặc định) đã ký ngắn: -32767 đến 32767 không dấu ngắn: 0 đến 65535 đã ký int: -32767 đến 32767 chưa ký int: 0 đến 65535 đã ký dài: -2147483647 đến 2147483647 dài không dấu: 0 đến 4294967295 dài không ký: -9223372036854775 0 đến 18446744073709551615 Việc triển khai C ++ (hoặc C) có thể xác định kích thước của một loại theo byte sizeof (loại) cho bất kỳ giá trị nào, miễn là

kích thước biểu thức (loại) * CHAR_BIT ước tính số lượng bit đủ để chứa các phạm vi yêu cầu và thứ tự loại vẫn hợp lệ (ví dụ sizeof (int) <= sizeof (dài)). Các phạm vi cụ thể triển khai thực tế có thể được tìm thấy trong tiêu đề trong C hoặc trong C ++ (hoặc thậm chí tốt hơn, templated std :: num_limits trong tiêu đề).

Ví dụ: đây là cách bạn sẽ tìm thấy phạm vi tối đa cho int:

C:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C ++:

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();

Điều này đúng, tuy nhiên, bạn cũng đã đúng khi nói rằng: char: 1 byte ngắn: 2 byte int: 4 byte dài: 4 byte float: 4 byte double: 8 byte

Bởi vì kiến ​​trúc 32 bit vẫn là mặc định và được sử dụng nhiều nhất, và chúng đã giữ các kích thước tiêu chuẩn này kể từ ngày trước 32 bit khi bộ nhớ còn ít hơn, và để tương thích ngược và tiêu chuẩn hóa vẫn giữ nguyên. Ngay cả các hệ thống 64 bit có xu hướng sử dụng những điều này và có phạm vi / sửa đổi. Vui lòng tham khảo điều này để biết thêm thông tin:

http://en.cppreference.com/w/cpp/lingu/types


0

Tôi nhận thấy rằng tất cả các câu trả lời khác ở đây hầu như chỉ tập trung vào các loại tích phân, trong khi người hỏi cũng hỏi về các dấu phẩy động.

Tôi không nghĩ rằng tiêu chuẩn C ++ yêu cầu nó, nhưng trình biên dịch cho các nền tảng phổ biến nhất hiện nay thường tuân theo tiêu chuẩn IEEE754 cho các số dấu phẩy động của chúng. Tiêu chuẩn này chỉ định bốn loại dấu phẩy động nhị phân (cũng như một số định dạng BCD, mà tôi chưa từng thấy hỗ trợ trong trình biên dịch C ++):

  • Độ chính xác một nửa (binary16) - Ý nghĩa 11 bit, phạm vi số mũ -14 đến 15
  • Độ chính xác đơn (binary32) - Ý nghĩa 24 bit, phạm vi số mũ -126 đến 127
  • Độ chính xác kép (binary64) - Ý nghĩa 53 bit, phạm vi số mũ -1022 đến 1023
  • Độ chính xác gấp bốn lần (binary128) - Ý nghĩa 113 bit, phạm vi số mũ -16382 đến 16383

Làm thế nào để bản đồ này vào các loại C ++, sau đó? Nói chung việc floatsử dụng độ chính xác duy nhất; do đó , sizeof(float) = 4. Sau đó, doublesử dụng độ chính xác kép (tôi tin rằng đó là nguồn gốc của tên double) vàlong double có thể là độ chính xác gấp đôi hoặc gấp bốn lần (nó tăng gấp bốn lần trên hệ thống của tôi, nhưng trên các hệ thống 32 bit có thể gấp đôi). Tôi không biết bất kỳ trình biên dịch nào cung cấp một nửa dấu phẩy động chính xác.

Tóm lại, đây là thông thường:

  • sizeof(float) = 4
  • sizeof(double) = 8
  • sizeof(long double) = 8 hoặc 16

Thật buồn cười là tôi đã đến câu hỏi này như một phần của việc tự hỏi tại sao Jeff sử dụng nhiều byte hơn mức anh ta cần.
Aniruddha Varma


-2

Bạn có thể sử dụng các biến được cung cấp bởi các thư viện như OpenGL , Qt , v.v.

Ví dụ: Qt cung cấp qint8 (được đảm bảo là 8 bit trên tất cả các nền tảng được Qt hỗ trợ), qint16, qint32, qint64, quint8, quint16, quint32, quint64, v.v.


1
Không trả lời câu hỏi
EvilTeach

-8

Trên máy 64 bit:

int: 4
long: 8
long long: 8
void*: 8
size_t: 8

2
Trên một số máy 64 bit intlà 8 byte, nhưng máy kia không được bảo đảm. Không có gì nói rằng charchỉ nên có 8 bit. Nó được phép có sizeof(void*)==4mặc dù là 64 bit.
skyking

-10

Có bốn loại số nguyên dựa trên kích thước:

  • số nguyên ngắn: 2 byte
  • số nguyên dài: 4 byte
  • số nguyên dài dài: 8 byte
  • số nguyên: phụ thuộc vào trình biên dịch (16 bit, 32 bit hoặc 64 bit)

11
Sai, tất cả đều phụ thuộc vào kiến ​​trúc, với các phạm vi tối thiểu được mô tả trong một trong những câu trả lời khác. Không có gì dừng lại một thực hiện có short, intlongtất cả các số nguyên 32 bit.
Matteo Italia

Bạn thậm chí không sử dụng tên chính xác cho các loại. Các tên sử dụng từ khóa int, không phải từ "số nguyên".
Keith Thompson
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.