2013-08-27 28 views
19

Tôi đã nhìn qua code golf và có một ý tưởng để thử mã này:Có thể định nghĩa một chỉ thị tiền xử lý khác không?

#define D #define sau khi thêm dòng này, mọi thứ đều hoạt động tốt, tuy nhiên tôi mở rộng nó vào đây:

#define D #define 
D VALUE 

Và ở đây tôi có 5 lỗi biên dịch. Nếu tôi thay đổi D thành #define mọi thứ đều ổn, ai đó có thể giải thích, tại sao mã này là bất hợp pháp?

LƯU Ý: Tôi đã sử dụng trình biên dịch VS2008.

EDIT: Sau một số câu trả lời tôi thấy rằng tôi cần thiết để cung cấp cho biên soạn danh sách lỗi:

  1. lỗi C2121: '#': nhân vật không hợp lệ: có thể là kết quả của một sự bành trướng vĩ mô
  2. lỗi C2146 : lỗi cú pháp: thiếu ';' trước số nhận dạng 'VALUE'
  3. lỗi C4430: thiếu thông số loại - int giả định. Lưu ý: C++ không hỗ trợ mặc định-int
  4. lỗi C2144: lỗi cú pháp: 'void' phải được bắt đầu bởi ';'
  5. lỗi C4430: thiếu thông số định kiểu - int giả định. Lưu ý: C++ không hỗ trợ mặc định-int

Lỗi đầu tiên cho thấy D không chỉ là define mà còn bao gồm #.

+0

Vì nó có thể phụ thuộc vào việc triển khai thực hiện, vui lòng nêu rõ trình biên dịch bạn đang sử dụng. –

+4

"tại sao mã này là bất hợp pháp?" - Bởi vì bạn không thể xác định lại chỉ thị tiền xử lý. –

+0

@ H2CO3 Tôi đã có thể xác định lại nó, bởi vì lần đầu tiên nó hoạt động, tuy nhiên sau khi sử dụng định nghĩa đó tôi nhận được lỗi biên dịch. – ST3

Trả lời

10

Mã này là bất hợp pháp vì đặc tả ngôn ngữ cho biết đó là bất hợp pháp. Theo đặc tả tiền xử lý C và C++, bất kỳ mã nào bạn xây dựng sử dụng bộ tiền xử lý sẽ không bao giờ được hiểu là một chỉ thị tiền xử lý khác. Tóm lại, bạn không thể xây dựng các chỉ thị tiền xử lý bằng cách sử dụng bộ tiền xử lý trước. Giai đoạn.

(Ngoài ra, bạn có thể không xây dựng ý kiến ​​sử dụng tiền xử lý.)

11

Dường như bộ tiền xử lý của bạn đang thực hiện thay thế bạn muốn, nhưng bạn có thể sẽ không nhận được hành vi bạn muốn - bộ tiền xử lý thường chỉ là một thao tác chuyển. Ví dụ (với kêu vang, nhưng bạn sẽ có thể để tái tạo bằng cách sử dụng những lá cờ VS2008 thích hợp):

$ cat example.c 
#define D #define 
D VALUE 
$ cc -P -E example.c 

#define VALUE 

Đó #define VALUE được đi thẳng thông qua để trình biên dịch, mà sẽ không biết phải làm gì với nó - đó là một chỉ thị tiền xử lý, sau khi tất cả. Lỗi của Clang, để tham khảo, tương tự như của bạn:

$ cc -c example.c 
example.c:2:1: error: expected identifier or '(' 
D VALUE 
^ 
example.c:1:11: note: expanded from macro 'D' 
#define D #define 
     ^
1 error generated. 
+15

Liệu bộ tiền xử lý có hoạt động một lần hay không là không liên quan. Bộ tiền xử lý sẽ không cần thực hiện nhiều lần quét tệp để xử lý lại các dòng riêng lẻ; nó chỉ có thể xử lý mỗi dòng nhiều lần nếu cần thiết. Trong thực tế, nó làm điều này: Macro thay thế được thực hiện nhiều lần. Lý do chỉ thị tiền xử lý không được xử lý sau khi thay thế macro là vì tiêu chuẩn ngôn ngữ nói không. –

+0

Yup, đã đồng ý. Không biết về các quy tắc chính thức. –

6

Điều đó sẽ không hoạt động vì tiền xử lý được thực hiện trong một lần truyền. Ví dụ, hãy xem xét các mã tiếp theo:

#define MYDEFINEWEIRD #define 

MYDEFINEWEIRD N 6 

int main() { 

    return 0; 
} 

Sau khi tiền xử lý, mã di chúc của bạn trông giống như:

#define N 6 
int main() { 

    return 0; 
} 

và "#define" không phải là một cú pháp hợp lệ trên C hoặc C++. Ngoài ra, vì chỉ thị tiền xử lý kết quả sẽ không được xử lý, nó sẽ không giải quyết các tham chiếu tiếp theo tới macro "N" trong mã của bạn.

Chỉ để cho vui, bạn có thể gọi trình tiền xử lý hai lần từ dòng lệnh bằng g ++/gcc. Xem xét mã tiếp theo (xác định.cpp):

#include <iostream> 

#define MYDEFINEWEIRD #define 
MYDEFINEWEIRD N 6 

using namespace std; 

int main() { 
    cout << N << endl; 
    return 0; 
} 

Sau đó, bạn có thể làm:

$ g++ -E define.cpp | g++ -o define -x c++ - && ./define 

và ý chí đầu ra:

6 
+2

"tiền xử lý được thực hiện trong một lần" - không, thực ra là không - và đây không phải là ** lý do lỗi. –

+2

@ H2CO3, tôi nghĩ kết quả của câu trả lời này có vẻ chính xác. –

+0

@EricPostpischil Vâng, đúng, nó nói rằng nó là một hoạt động vượt qua duy nhất. Nhưng nó không phải là, phải không? '#define FOO BAR', sau đó' #define BAR 0', sau đó 'return FOO;' mở rộng thành 'return 0;' cho tôi. –

31

C 2011 (N1570) 6.10.3.4 3: “Các kết quả hoàn toàn vĩ mô thay thế trình tự mã thông báo tiền xử lý không được xử lý như một chỉ thị tiền xử lý ngay cả khi nó giống như một,… ”

C++ 2010 (N309 2) 16.3.4 [cpp.rescan] 3 có cùng nội dung giống nhau.

+2

Đây là câu trả lời đúng. Tiêu chuẩn ngôn ngữ C chỉ định thứ tự chính xác của các hoạt động trong cách mã nguồn chương trình được dịch. –

+1

Điều này "ngay cả khi nó giống như một" văn bản đi trở lại tiêu chuẩn ANSI C 1989 (và có khả năng nhất dự thảo trước đó). – Kaz

+0

N3092 không phải là một tiêu chuẩn ... mặc dù văn bản chắc chắn là giống nhau trong C++ 98, C++ 11 và mọi bản nháp tiêu chuẩn C++ đã từng hoặc sẽ từng có. – Potatoswatter

1

dòng mã trong các xưởng sơ chế mắt là một trong hai báo cáo tiền xử lý (Và như vậy, không có bất kỳ thay thế được thực hiện trên chúng) hoặc văn bản bình thường báo cáo (Và có thay thế được thực hiện). Bạn không thể có được cả hai, vì vậy một khi bạn có 'D' được thay thế nó chỉ sẽ xem xét để xem nếu có thêm bất kỳ macro để thay thế. Vì không có, nó chỉ để lại '#define' trong mã C++ vì nó và sau đó trình biên dịch C++ sẽ gặp lỗi khi nó thấy nó (Vì '#define' không phải là mã C++ hợp lệ).

Vì thế hãy cho quan điểm của tôi nhiều hơn, đây là mã không hợp lệ cho tiền xử lý:

#define D define 
#D value 

Bởi vì trước xử lý không làm bất kỳ thay thế vĩ mô trên báo cáo trước bộ xử lý, và "#D ngoại" không phải là lệnh được xử lý trước được công nhận. Và điều này:

#define D #define 
D value 

Kết quả trong C++ này mã:

#define value 

Đó là không hợp lệ vì tiền xử lý đã được thực hiện được chạy.

1

Nhìn vào ngữ pháp trong 16 [cpp] đoạn 1, một sự thay thế danh sách gồm pp-tokens có thể bao gồm việc sản xuất # không chỉ được mô tả trong đoạn 2 của cùng một đoạn như

Không chỉ thị sẽ không bắt đầu với bất kỳ tên chỉ thị nào xuất hiện trong danh sách.

Đó là, một cái gì đó có dạng

#define NAME # define 

sẽ xảy ra là bất hợp pháp! Cũng lưu ý rằng # trong ngữ cảnh này không không phải là chuyển từ tiếp theo thành chuỗi: trích dẫn sau # chỉ xảy ra sau khi # được theo sau bởi tên thông số macro trong macro kiểu hàm.

+0

Ký hiệu ngữ pháp 'không chỉ thị' trong câu “Không chỉ thị không bắt đầu…” là một dòng '# không chỉ thị'. Vì vậy, nó chỉ đơn thuần là phân biệt các dòng giống như '# some-directive' từ các dòng trông giống như' # non-directive'. Điều này không làm cho '#define NAME # define' là một chuỗi mã thông báo tiền xử lý không hợp lệ. –

Các vấn đề liên quan