Câu hỏi Tại sao chiều dài tối đa của chuỗi C khác với chữ cái tối đa char []?


Làm rõ: Cho rằng một chuỗi chữ có thể được viết lại như một const char[] (xem bên dưới), áp đặt độ dài tối đa thấp hơn cho các chữ hơn là trên char[]s chỉ là một sự bất tiện cú pháp. Tại sao tiêu chuẩn C khuyến khích điều này?


Chuẩn C89 có giới hạn dịch đối với các chuỗi ký tự:

509 ký tự trong một chuỗi ký tự bằng chữ hoặc chuỗi chữ lớn (sau khi ghép)

Không có giới hạn cho một mảng char; có lẽ

32767 byte trong một đối tượng (chỉ trong môi trường được lưu trữ)

áp dụng (Tôi không chắc chắn về đối tượng hoặc môi trường lưu trữ có nghĩa là gì), nhưng ở bất kỳ mức nào, đó là giới hạn cao hơn nhiều.

Sự hiểu biết của tôi là một chuỗi ký tự tương đương với mảng char chứa các ký tự, nghĩa là: luôn có thể viết lại một cái gì đó như thế này:

const char* str = "foo";

vào cái này

static const char __THE_LITERAL[] = { 'f', 'o', 'o', '\0' };
const char* str = __THE_LITERAL;

Vậy tại sao một giới hạn cứng như vậy về chữ?


14
2017-07-15 01:10


gốc


Thật kỳ lạ khi họ chọn 509 thay vì 65533 hoặc 253. - Seth Carnegie
Bạn có thể đọc bài viết này: msdn.microsoft.com/en-us/library/sx08afx2.aspx - Richard J. Ross III
Giới hạn về chương trình nguồn không có gì để làm với các giới hạn về chương trình đã biên dịch. - n.m.
@ SethCarnegie: Có lẽ 509 được thiết kế để cho phép một bộ đệm 512 byte với hai byte cho một "\r\n" dòng terminator và một cho một '\0' chuỗi terminator. - Keith Thompson


Các câu trả lời:


Giới hạn về chuỗi ký tự là một yêu cầu biên dịch; có một giới hạn tương tự về độ dài của một đường nguồn logic. Trình biên dịch có thể sử dụng cấu trúc dữ liệu có kích thước cố định để giữ các dòng nguồn và các chuỗi ký tự chuỗi.

(C99 tăng các giới hạn cụ thể này từ 509 lên 4095 ký tự.)

Mặt khác, một đối tượng (chẳng hạn như một mảng char) có thể được xây dựng trong thời gian chạy. Các giới hạn có thể được áp đặt bởi kiến ​​trúc máy đích, không phải do thiết kế của trình biên dịch.

Lưu ý rằng đây là không phải giới hạn trên áp dụng cho các chương trình. Trình biên dịch không bắt buộc phải áp đặt bất kỳ giới hạn hữu hạn nào cả. Nếu trình biên dịch áp đặt giới hạn về độ dài của dòng, nó phải có ít nhất 509 hoặc 4095 ký tự. (Hầu hết các trình biên dịch thực tế, tôi nghĩ, không áp đặt giới hạn cố định, thay vì chúng phân bổ bộ nhớ động.)


16
2017-07-15 01:26



Mặc dù tất nhiên có một giới hạn thực tế - nếu trình biên dịch là một thực thi 32-bit, nó chắc chắn sẽ không thể xử lý một chuỗi chữ trên 4G (định dạng tập tin đối tượng hạn chế mặc dù). Giới hạn thực tế của khóa học sẽ thấp hơn nhiều. - Adam Rosenfield
Không phải là khởi tạo const char[] được xây dựng tại thời gian biên dịch quá? - npostavs
@npostavs: Có thể, nhưng giới hạn 32767 byte (tăng lên 65536 trong C99) áp dụng cho các đối tượng thời gian chạy, bất kể chúng được xây dựng như thế nào. - Keith Thompson


Nó không phải là 509 ký tự là giới hạn cho một chuỗi, đó là yêu cầu tối thiểu cho khả năng tương thích ANSI, như được giải thích đây.

Tôi nghĩ rằng các nhà sản xuất tiêu chuẩn đã kéo số 509 ra khỏi ass của họ, nhưng trừ khi chúng tôi nhận được một số tài liệu chính thức từ điều này, không có cách nào để chúng tôi biết.

Theo như bao nhiêu ký tự thực sự có thể được trong một chuỗi chữ, đó là phụ thuộc vào trình biên dịch.

Dưới đây là một số ví dụ:

  • MSVC: 2048
  • GCC: Không giới hạn (tối đa 100.000 ký tự), nhưng cảnh báo sau 510 ký tự:

Chuỗi ký tự có độ dài 100000 vượt quá độ dài tối đa 509 mà trình biên dịch C90 được yêu cầu hỗ trợ


4
2017-07-15 01:25



Thông tin thú vị, nhưng nó không thực sự trả lời câu hỏi. - Keith Thompson
@KeithThompson Tôi không đồng ý. Nó trả lời câu hỏi ở chỗ nó giải thích rằng nó không phải là một 'giới hạn', nhưng là 'tối thiểu', vì vậy trên hầu hết các trình biên dịch, sẽ không có sự khác biệt. - Richard J. Ross III
Tôi nghĩ điểm mấu chốt là 509 được tham chiếu trong tiêu chuẩn là tối thiểu, không phải là tối đa. - Michael Mior
@npostavs Tôi nghĩ đó là nơi bạn không chính xác. A const char * khác nhiều so với khởi tạo const char [], đặc biệt là nơi nó nằm trong bộ nhớ. - Richard J. Ross III
@ RichardJ.RossIII, về bình luận của bạn về nơi 509 đến từ: Tôi không nghĩ rằng đó là từ ass của một ai đó. Đó là 509 ký tự, để lại chỗ cho một ký tự kết thúc chuỗi một byte (\0) và một con trỏ hai byte. Ít nhất, đó là phỏng đoán của tôi. - Richard


Xin lỗi về câu trả lời muộn, nhưng tôi muốn minh họa sự khác biệt giữa hai trường hợp (Richard J. Ross đã chỉ ra rằng chúng không tương đương.)

Giả sử bạn thử điều này:

const char __THE_LITERAL[] = { 'f', 'o', 'o', '\0' };
const char* str = __THE_LITERAL;
char *str_writable = (char *) str;  // Not so const anymore
str_writable[0] = 'g';

Hiện nay str chứa "goo".

Nhưng nếu bạn làm điều này:

const char* str = "foo";
char *str_writable = (char *) str;
str_writable[0] = 'g';

Kết quả: segfault! (trên nền tảng của tôi, ít nhất.)

Đây là sự khác biệt cơ bản: Trong trường hợp đầu tiên bạn có một mảng được khởi tạo thành "foo", nhưng trong trường hợp thứ hai bạn có một chuỗi ký tự thực tế.

Còn một chú ý đáng nói,

const char __THE_LITERAL[] = { 'f', 'o', 'o', '\0' };

tương đương với

const char __THE_LITERAL[] = "foo";

Ở đây = hoạt động như một bộ khởi tạo mảng thay vì gán. Điều này rất khác với

const char *str = "foo";

nơi mà địa chỉ của chuỗi ký tự được gán cho str.


1
2018-01-18 09:47



Oh, tôi có nghĩa là cho __THE_LITERAL là một biến tĩnh, trong đó trường hợp segfault kết quả trong cả hai trường hợp. - npostavs
@npostavs: Hmm, bạn nói đúng. Hấp dẫn. Thực ra tôi đã nhầm lẫn về = "foo" được đối xử chính xác như = {'f','o','o','\0'}. Nếu tôi làm điều tương tự bằng cách sử dụng hơn 509 ký tự, gcc sẽ đưa ra cảnh báo trong trường hợp đầu tiên nhưng không đưa ra cảnh báo thứ hai. Tôi đoán đó là vì những gì Keith Thompson đã nói ở trên - các trình biên dịch có thể sử dụng các cấu trúc dữ liệu kích thước cố định để xử lý các chữ. - Yakov Shklarov