Tại sao chuyển đổi từ hằng chuỗi thành 'char *' hợp lệ trong C nhưng không hợp lệ trong C ++


162

Tiêu chuẩn C ++ 11 (ISO / IEC 14882: 2011) cho biết § C.1.1:

char* p = "abc"; // valid in C, invalid in C++

Đối với C ++, việc dùng con trỏ cho Chuỗi ký tự là có hại vì mọi nỗ lực sửa đổi đều dẫn đến sự cố. Nhưng tại sao nó có giá trị trong C?

C ++ 11 cũng nói:

char* p = (char*)"abc"; // OK: cast added

Điều đó có nghĩa là nếu một diễn viên được thêm vào câu lệnh đầu tiên thì nó trở nên hợp lệ.

Tại sao việc truyền làm cho câu lệnh thứ hai có giá trị trong C ++ và nó khác với câu lệnh thứ nhất như thế nào? Nó vẫn không gây hại sao? Nếu đúng như vậy, tại sao tiêu chuẩn lại nói rằng nó ổn?


3
C ++ 11 không cho phép cái đầu tiên. Tôi không biết tại sao C lại tạo ra một chuỗi ký tự theo nghĩa đen char[]. Cái thứ hai là một sự const_castngụy trang.
chris

4
Đơn giản là có quá nhiều mã C kế thừa sẽ bị phá vỡ nếu quy tắc này được thay đổi.
Paul R

1
xin vui lòng trích dẫn văn bản trong đó Tiêu chuẩn nói thứ hai là OK.
Nawaz

13
Ngôn ngữ C có chuỗi ký tự trước đó const, vì vậy chúng không nhất thiết phải như vậy const.
Casey

2
C và C ++ cho phép bạn chuyển từ gần như bất kỳ loại nào sang loại khác. Điều đó không có nghĩa là những diễn viên này có ý nghĩa và an toàn.
Siyuan Ren

Câu trả lời:


206

Cho đến C ++ 03, ví dụ đầu tiên của bạn là hợp lệ, nhưng đã sử dụng một chuyển đổi ngầm không được chấp nhận - một chuỗi ký tự nên được coi là thuộc loại char const *, vì bạn không thể sửa đổi nội dung của nó (mà không gây ra hành vi không xác định).

Kể từ C ++ 11, chuyển đổi ngầm đã bị phản đối đã chính thức bị xóa, do đó, mã phụ thuộc vào nó (như ví dụ đầu tiên của bạn) sẽ không còn được biên dịch nữa.

Bạn đã lưu ý một cách để cho phép mã biên dịch: mặc dù chuyển đổi ngầm đã bị xóa, một chuyển đổi rõ ràng vẫn hoạt động, do đó bạn có thể thêm một lần truyền. Tuy nhiên, tôi sẽ không xem xét việc "sửa" mã này.

Việc sửa mã thực sự đòi hỏi phải thay đổi loại con trỏ thành đúng loại:

char const *p = "abc"; // valid and safe in either C or C++.

Về lý do tại sao nó được cho phép trong C ++ (và vẫn ở C): đơn giản vì có rất nhiều mã hiện có phụ thuộc vào chuyển đổi ngầm định đó và phá vỡ mã đó (ít nhất là không có cảnh báo chính thức) dường như đối với các ủy ban tiêu chuẩn như một ý tưởng tồi.


8
@rullof: Nó đủ nguy hiểm để nó không mang lại bất kỳ sự linh hoạt có ý nghĩa nào, ít nhất là đối với mã quan tâm (tất cả) về tính di động. Viết theo một chuỗi ký tự thông thường sẽ khiến chương trình của bạn bị hủy bỏ trên một hệ điều hành hiện đại, do đó, cho phép mã (cố gắng) viết ở đó không thêm bất kỳ tính linh hoạt có ý nghĩa nào.
Jerry Coffin

3
Đoạn mã được đưa ra trong câu trả lời char const *p = "abc";này là "hợp lệ và an toàn trong cả C C ++", không "hợp lệ và an toàn trong cả C hoặc C ++".
Daniel Le

4
@DanielLe cả hai câu đó đều có cùng một nghĩa
Caleth

3
Ôi chúa ơi! [Chèn lưỡi chắc chắn vào má] Xin lỗi, nhưng "hoặc" là thuật ngữ chính xác ở đây. Mã có thể được biên dịch thành C hoặc C ++, nhưng không thể được biên dịch đồng thời cả C và C ++. Bạn có thể chọn một trong hai, nhưng bạn phải lựa chọn. Bạn không thể có cả hai cùng một lúc. [tiếp tục hoạt động lưỡi bình thường].
Jerry Coffin

2
Không, cả / và là từ ngữ rõ ràng và đúng nhất ở đây. Hoặc / hoặc cũng xảy ra để truyền đạt ý nghĩa đúng, nhưng nó không rõ ràng về mặt kỹ thuật. Hoặc một mình là sai không thể chối cãi ( A hoặc B không bằng A và B ).
Apollys hỗ trợ Monica

15

Nó hợp lệ trong C vì lý do lịch sử. Theo truyền thống, C quy định rằng loại chuỗi ký tự char *thay vì const char *, mặc dù nó đủ điều kiện bằng cách nói rằng bạn thực sự không được phép sửa đổi nó.

Khi bạn sử dụng ép kiểu, về cơ bản, bạn nói với trình biên dịch rằng bạn biết rõ hơn các quy tắc khớp loại mặc định và nó làm cho phép gán được.


3
Đó là một char[N]và đã được thay đổi thành const char[N]. Nó có thông tin kích thước kèm theo nó.
chris

1
Trong C loại chuỗi ký tự là char[N]nhưng không char*ví dụ "abc"char[4]
Grijesh Chauhan

2

Bạn cũng có thể sử dụng strdup :

char* p = strdup("abc");
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.