2017-02-16 20 views
16

Định nghĩa thường được sử dụng của đơn vị dịch là những gì xuất hiện sau khi xử lý trước (bao gồm các tệp tiêu đề, macro, v.v. cùng với tệp nguồn). Định nghĩa này là hợp lý rõ ràng và tiêu chuẩn C, 5.1.1.1, C11, nói:Đơn vị dịch chính xác là gì ở C

Một chương trình C không cần phải dịch cùng một lúc. Văn bản của chương trình được lưu giữ trong các đơn vị được gọi là các tệp nguồn, (hoặc các tệp tiền xử lý) trong tiêu chuẩn này. Tệp nguồn cùng với tất cả các tiêu đề và tệp nguồn được bao gồm qua chỉ thị tiền xử lý #include được biết đến như một đơn vị dịch tiền xử lý. Sau khi tiền xử lý, một đơn vị dịch tiền xử lý được gọi là đơn vị dịch thuật.

Đọc câu đầu tiên chặt chẽ hơn:

Một chương trình C cần không phải tất cả được dịch cùng một lúc.

trong đó hàm ý (để đọc sách của tôi), một chương trình C thể được dịch đồng mà không nhất thiết phải tách chúng thành nhiều file nguồn tiền xử lý. Cũng ở cuối cùng một đoạn, tiêu chuẩn cho biết:

Đơn vị dịch có thể được dịch riêng và sau đó được liên kết để tạo chương trình thực thi.

có thể (và thường là) được hiểu là biên dịch các tệp đối tượng riêng lẻ và sau đó liên kết chúng để tạo ra một chương trình thực thi duy nhất. Tuy nhiên, nếu người ta có thể làm cho một câu hỏi ra khỏi tuyên bố trên và yêu cầu: có nghĩa là một thực hiện là miễn phí để xem xét nhiều file nguồn như một đơn vị dịch duy nhất, đặc biệt đối với một lời gọi như:

gcc file1.c file2.c -o out 

nơi trình biên dịch có quyền truy cập vào toàn bộ nguồn?

Cụ thể, nếu việc triển khai xử lý file1.c + file2.c (ở trên) dưới dạng đơn vị dịch đơn, có thể coi là không phù hợp không?

+2

Tiêu chuẩn có nghĩa đen không có gì để nói về giải thích của GCC về các đối số dòng lệnh của GCC. Đó là bình thường trong phạm vi của ISO C, vì vậy nó thậm chí không được thực hiện xác định trong ý nghĩa của tiêu chuẩn. –

+1

Hoàn toàn có thể viết mã phù hợp để biên dịch và liên kết sạch miễn là hai tệp được coi là đơn vị dịch riêng biệt, nhưng sẽ không biên dịch được nếu chúng được coi là một TU Ví dụ, các tệp có thể xác định chức năng tĩnh có cùng tên; nếu được coi là một TU đơn, thì hỗn hợp sẽ có chức năng đó được định nghĩa nhân. –

+1

@IwillnotexistIdonotexist GCC (cộng với thư viện, nền tảng vv) là một * triển khai * và liệu, nếu có, GCC (hoặc bất kỳ trình biên dịch nào) làm như vậy sẽ được coi là không phù hợp là câu hỏi. Trong thực tế, không có gì trong câu hỏi hỏi về hành vi của GCC khác bằng cách sử dụng nó như là một ví dụ cho lệnh biên dịch. – usr

Trả lời

7

Tuy nhiên, nếu ai có thể làm cho một câu hỏi ra khỏi tuyên bố trên và yêu cầu: có nghĩa là một thực hiện là miễn phí để xem xét nhiều file nguồn như một đơn vị dịch đơn

số Định nghĩa là rõ ràng:

một tập tin nguồn cùng với tất cả các tiêu đề và các tập tin nguồn bao gồm thông qua #include chỉ thị tiền xử lý được biết đến như một đơn vị tiền xử lý dịch. Sau khi tiền xử lý, một đơn vị dịch tiền xử lý được gọi là đơn vị dịch thuật.

Đơn vị dịch là kết quả của việc xử lý trước tệp nguồn và bao gồm. Thực tế là bạn có thể dịch hai đơn vị dịch thuật cùng một lúc không có nghĩa là bạn có thể coi chúng là một đơn vị dịch thuật.

12

Trong dòng thứ hai bạn trích dẫn:

Các văn bản của chương trình được lưu giữ trong đơn vị gọi là file nguồn, (hoặc các tập tin tiền xử lý) trong tiêu chuẩn quốc tế

Nếu có hai nguồn này các tệp sau đó có hai tệp tiền xử lý và do đó có hai đơn vị dịch tiền xử lý và do đó có hai đơn vị dịch. Một cái tương ứng với mỗi tệp nguồn.

Chuẩn không xác định tệp nguồn. Tôi đoán trình biên dịch có thể nói "Tôi đang tạo phiên bản 'tệp nguồn' của riêng mình bằng cách tuyên bố rằng file1.cfile2.c không phải là tệp nguồn sau tất cả!" và nối chúng lại, nhưng điều này có thể là mâu thuẫn với những kỳ vọng của lập trình viên. Tôi nghĩ rằng bạn sẽ có một thời gian khó khăn cho rằng file1.c không phải là một tập tin nguồn.

+1

Trình biên dịch không thể làm điều đó một cách tùy ý. Nó có thể ghi lại hành vi, trong trường hợp lập trình viên cẩn thận luôn đọc tài liệu trước khi triển khai một trình biên dịch mới đã điều chỉnh các kỳ vọng của họ (hoặc quay lại trình biên dịch với hành vi thông thường hơn). – rici

+1

@rici câu hỏi là liệu nó sẽ vi phạm tiêu chuẩn nếu trình biên dịch đã làm điều đó; nếu bạn giải thích từ "tệp nguồn" trong tiêu chuẩn có nghĩa là "kết quả của các tệp nối được chỉ ra bởi các đối số dòng lệnh" thì trình biên dịch có thể thực hiện điều đó. –

+2

tôi nghĩ rằng nó sẽ là hợp pháp cho một trình biên dịch để xác định tập tin nguồn như là nối của các đối số. Nhưng đó là hành vi được thực hiện do đó nó chỉ hợp pháp nếu được ghi lại. Tương tự, một trình biên dịch thông thường hơn phải xác định rằng mỗi tệp được đặt tên trong dòng lệnh được coi là một đơn vị dịch riêng biệt và bạn có thể sẽ tìm thấy câu lệnh đó nếu bạn tìm kiếm nó. – rici

5

Đơn vị dịch có nghĩa là tệp C chấm. Đối với tất cả ý định và mục đích, kể cả dấu chấm liên quan của nó bao gồm. Hiếm khi #include chỉ thị được sử dụng để thêm các loại tệp khác hoặc các tệp C chấm khác.

biến tĩnh chỉ hiển thị trong đơn vị dịch. Nó rất phổ biến để có một vài chức năng công cộng với liên kết bên ngoài và nhiều chức năng tĩnh và các mục dữ liệu t hỗ trợ. Vì vậy, một đơn vị dịch C là một chút giống như một lớp đơn C++. Nếu trình biên dịch không xử lý tĩnh chính xác thì nó không phù hợp.

Thông thường, một tệp đối tượng được tạo cho mỗi đơn vị dịch và sau đó chúng được liên kết bởi trình liên kết. Đó không phải là thực sự bắt buộc bởi tiêu chuẩn nhưng là cách tự nhiên và rõ ràng để làm mọi thứ trong môi trường nơi các tệp có giá rẻ để tạo và biên dịch tương đối chậm.

+0

Để khiêu khích: Hôm nay tôi cho rằng biên dịch là tương đối nhanh (bao nhiêu lõi?) Nhưng việc tạo tệp là tốn kém ;-). Trên thực tế, đó có thể là trường hợp tất cả cùng: Tôi sử dụng để biên dịch trên một đĩa RAM trên Atari ST của tôi bởi vì lưu trữ khối lượng là một đĩa mềm. –

5

Trình biên dịch được tự do dịch nhiều tệp nguồn cùng một lúc, nhưng chúng không thể thay đổi ngữ nghĩa của chúng.

Dịch nhiều tệp cùng nhau có thể sẽ nhanh hơn một chút (vì trình biên dịch chỉ bắt đầu một lần) và sẽ cho phép tối ưu hóa toàn bộ chương trình tốt hơn: Mã nguồn của các hàm được gọi trong đơn vị dịch khác sau đó có sẵn tại điểm gọi từ các đơn vị dịch khác . Trình biên dịch có thể kiểm tra mã được gọi và sử dụng thông tin, nhiều như nó có thể với một đơn vị dịch duy nhất. From the gcc 6.3.0 manual:

Trình biên dịch thực hiện tối ưu hóa dựa trên kiến ​​thức của chương trình. Biên dịch nhiều tệp cùng một lúc sang một chế độ tệp đầu ra duy nhất cho phép trình biên dịch sử dụng thông tin giành được từ tất cả các tệp khi biên dịch từng tệp.

Chức năng được gọi có thể được kiểm tra nếu không có răng cưa, thực tế của các đối tượng được chỉ định, vv, cho phép trình biên dịch thực hiện tối ưu hóa sẽ sai trong trường hợp chung.

Và, tất nhiên, các chức năng như vậy có thể được gạch chân.

Nhưng có các ngữ nghĩa của các đơn vị dịch (tiền xử lý) (tương ứng với các tệp nguồn sau khi tiền xử lý, theo báo giá chuẩn của bạn) mà trình biên dịch phải tôn trọng. @ Malcolm đề cập đến một, biến tập tin tĩnh. Cảm giác ruột của tôi là có thể có các vấn đề khác, tinh tế hơn liên quan đến khai báo và thứ tự khai báo.

Một mối quan tâm về vấn đề phạm vi mã nguồn rõ ràng khác xác định. Từ dự thảo n1570, 6.10.3.5:

Một định nghĩa vĩ mô kéo dài (không phụ thuộc vào cấu trúc khối) cho đến khi một #undef chỉ thị tương ứng được gặp hoặc (nếu không được gặp) cho đến khi kết thúc của tiền xử lý dịch đơn vị.

Cả hai vấn đề đều cấm ghép nối tệp nguồn C đơn giản; trình biên dịch phải áp dụng thêm một số logic thô sơ.