Trong this article từ Guru trong tuần, người ta nói: It is illegal to #define a reserved word.
Điều này có đúng không? Tôi không thể tìm thấy bất cứ điều gì trong tiêu chuẩn, và tôi đã thấy các lập trình viên xác định lại mới, ví dụ.Có hợp pháp để xác định lại từ khóa C++ không?
Trả lời
17.4.3.1.1 tên Macro [lib.macro.names]
1 Each name defined as a macro in a header is reserved to the implementation for any use if the translation unit includes the header.164)
2 A translation unit that includes a header shall not contain any macros that define names declared or defined in that header. Nor shall such a translation unit define macros for names lexically identical to keywords.
Bằng cách này, new
là một nhà điều hành và nó có thể bị quá tải (thay thế) của người dùng bằng cách cung cấp riêng của mình phiên bản.
Lưu ý rằng quy tắc đó chỉ áp dụng cho các nguồn bao gồm tiêu đề chuẩn. Hoàn toàn hợp pháp để xác định lại từ khóa nếu đơn vị dịch không bao gồm tiêu đề chuẩn. (Tuy nhiên, nó không làm nhiều cho khả năng đọc của mã.) –
Vì vậy, tôi được phép '#define new' miễn là đơn vị dịch của tôi không có tiêu đề: P? @JamesKanze: tại sao ** tiêu đề ** tiêu đề? – qdii
@victor: thư viện chuẩn (mẫu) ?? – ted
Nó không phải như xa như tôi biết bất hợp pháp - không có trình biên dịch tôi đã đi qua nhưng sẽ tạo ra lỗi nếu bạn làm
#define true false
#defining
từ khóa nhất định có nhiều khả năng để tạo ra sai sót trong lập vì những lý do khác . Nhưng rất nhiều trong số họ sẽ chỉ dẫn đến hành vi của chương trình rất lạ.
Các định nghĩa như vậy có thể gây ra vấn đề với thư viện chuẩn. –
Có thể, trên một số bộ phận. Vấn đề tôi có là mặc dù nó là bất hợp pháp, dường như không có bất kỳ yêu cầu nào cho trình biên dịch đưa ra một chẩn đoán. Và tùy thuộc vào bit của thư viện chuẩn mà bạn sử dụng và nơi bạn đặt #define trong mã của mình, chương trình có thể biên dịch tốt. –
Giống như rất nhiều thứ, đó là hành vi không xác định. Nó sẽ không khó khăn cho một trình biên dịch để phát hiện nó, và gây ra một lỗi thời gian biên dịch, nhưng tôi không biết bất kỳ điều gì làm. –
Phần tương ứng từ C++ 11:
17.6.4.3.1 tên Macro [macro.names]
1 A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
2 A translation unit shall not #define or #undef names lexically identical to keywords.
Khoản 1 từ C++ 03 đã được gỡ bỏ. Đoạn thứ hai đã được chia làm hai. Nửa đầu hiện đã được thay đổi để nêu rõ rằng nó chỉ áp dụng cho các tiêu đề tiêu chuẩn tiêu chuẩn. Điểm thứ hai đã được mở rộng để bao gồm bất kỳ đơn vị dịch nào, không chỉ đơn vị dịch bao gồm các tiêu đề.
Tuy nhiên, Tổng quan cho phần này của tiêu chuẩn (17.6.4.1 [constraints.overview]) khẳng định:
This section describes restrictions on C++ programs that use the facilities of the C++ standard library.
Do đó, nếu bạn không sử dụng Thư viện C++ chuẩn, sau đó bạn không sao để làm những gì bạn sẽ làm. Vì vậy, để trả lời câu hỏi của bạn trong ngữ cảnh của C++ 11: bạn không thể xác định (hoặc không xác định) bất kỳ tên nào giống hệt với từ khóa trong bất kỳ đơn vị dịch nào nếu bạn đang sử dụng thư viện chuẩn C++.
+1: thú vị – qdii
Đây là một điều nhỏ bạn có thể làm nếu bạn không muốn ai đó sử dụng goto. Chỉ cần thả sau đây một nơi nào đó trong mã của mình, nơi ông sẽ không nhận thấy nó.
#define goto { int x = *(int *)0; } goto
Bây giờ mỗi khi anh ta cố gắng sử dụng câu lệnh goto, chương trình của anh ấy sẽ bị lỗi.
Chúng thực sự sai ở đó, hoặc ít nhất không kể toàn bộ câu chuyện về nó. Lý do thực sự nó không được phép là nó vi phạm quy tắc một định nghĩa (mà bằng cách này cũng được đề cập như là lý do thứ hai tại sao nó bất hợp pháp). Để thấy rằng nó thực sự được phép (để xác định lại từ khóa), ít nhất là nếu bạn không sử dụng các thư viện chuẩn, bạn phải xem xét một phần hoàn toàn khác của tiêu chuẩn, cụ thể là các giai đoạn dịch thuật. Nó nói rằng đầu vào chỉ bị phân tách thành các thẻ tiền xử lý trước khi tiền xử lý diễn ra và nhìn vào chúng không có sự phân biệt giữa private
và fubar
, chúng đều là identifiers
với bộ tiền xử lý trước.Sau đó khi đầu vào được phân tách thành token
, thay thế đã được thực hiện. Nó đã được chỉ ra rằng có một hạn chế về các chương trình được sử dụng các thư viện chuẩn, nhưng nó không phải là hiển nhiên rằng ví dụ redefining private
là làm điều đó (như trái ngược với "Người # 4: The Language Lawyer" đoạn mã sử dụng nó cho đầu ra để cout
).
Nó được đề cập trong ví dụ cuối cùng rằng mẹo không bị chà đạp bởi các đơn vị dịch thuật hoặc xe điện khác. Với điều này trong tâm trí bạn có lẽ nên xem xét khả năng rằng các thư viện chuẩn đang được sử dụng ở một nơi khác mà sẽ đặt hạn chế này có hiệu lực.
Hoàn toàn có thể sử dụng '# define' để thay đổi ý nghĩa của các từ dành riêng. Trên thực tế, nó thường được sử dụng trong các mục [Cuộc thi viết mã C bị quấy nhiễu quốc tế] (http://www.ioccc.org/). Có thể vì các macro được định nghĩa bởi '# define' được thay thế bởi một chương trình riêng biệt trước khi trình biên dịch C thực sự chạy. –
chắc chắn họ không quá tải toán tử mới? vì bộ tiền xử lý chạy trước tiên, vấn đề với các từ khóa "# define" -ing là bạn thay thế các từ khóa bằng chuỗi thay thế của bạn, mã không mong đợi điều này rất có thể sẽ bị hỏng ở đó sau đó. Nó thường là một ý tưởng tồi để làm như vậy, tại sao bạn sẽ muốn làm điều đó không? – ted
@ted: ý tưởng là xác định lại từ khóa mới trong tệp nguồn để gọi triển khai nền tảng cụ thể: '#define newMac' mới trên Macintosh và' #define newPc' mới trên PC. Trong các đơn vị dịch khác, các hàm tương ứng sẽ xác định các bộ cấp phát bộ nhớ cụ thể cho nền tảng. Tôi đoán ý tưởng là tiếp tục sử dụng 'mới' ở mọi nơi trong khi có hành vi cụ thể cho nền tảng khi không thể đổi tên mọi cuộc gọi thành mới. – qdii