Không có dòng mới nào ở cuối tập tin Cảnh báo trình biên dịch


187

Lý do cảnh báo sau trong một số trình biên dịch C ++ là gì?

Không có dòng mới ở cuối tệp

Tại sao tôi nên có một dòng trống ở cuối tệp nguồn / tiêu đề?


17
Không thực sự là lý do, nhưng sẽ rất khó chịu nếu bạn catlà một tệp và nó không có dòng mới vì dấu nhắc shell mới sẽ xuất hiện sau dòng cuối cùng của tệp (không phải trong cột 0)
ThiefMaster

@ThiefMaster $ PS1 của tôi bắt đầu với một dòng mới vì lý do đó. (dù sao đó cũng là một dấu nhắc nhiều dòng, chứa một loạt thông tin hữu ích trên một dòng và sau đó không có gì ngoài một ký tự nhắc nhở tiếp theo để các lệnh khá dài không bao bọc)
bames53

7
Why should I have an empty line at the end of a source/header file- Nếu một tệp văn bản chứa one\ntwo\nthree\nthì nó chứa ba dòng, không có dòng nào trống. Nếu một tệp văn bản chứa one\ntwo\nthreethì đó không phải là một tệp văn bản, theo nghĩa tương tự rằng một câu không có điểm dừng hoàn toàn ở cuối không phải là một câu.
Brandin

Câu trả lời:


217

Hãy nghĩ về một số vấn đề có thể xảy ra nếu không có dòng mới. Theo tiêu chuẩn ANSI, #includetập tin lúc đầu sẽ chèn tập tin chính xác vào phía trước tập tin và không chèn dòng mới vào #include <foo.h>sau nội dung của tập tin. Vì vậy, nếu bạn bao gồm một tệp không có dòng mới ở cuối trình phân tích cú pháp, nó sẽ được xem như là dòng cuối cùng foo.hnằm trên cùng dòng với dòng đầu tiên foo.cpp. Điều gì sẽ xảy ra nếu dòng cuối cùng của foo.h là một bình luận không có dòng mới? Bây giờ dòng đầu tiên foo.cppđược nhận xét. Đây chỉ là một vài ví dụ về các loại vấn đề có thể leo lên.


Chỉ muốn chỉ ra bất kỳ bên quan tâm đến câu trả lời của James dưới đây. Mặc dù câu trả lời trên vẫn đúng với C, nhưng tiêu chuẩn C ++ mới (C ++ 11) đã được thay đổi để cảnh báo này không còn được đưa ra nếu sử dụng C ++ và trình biên dịch tuân thủ C ++ 11.

Từ tiêu chuẩn C ++ 11 qua bài đăng của James:

Một tệp nguồn không trống và không kết thúc bằng một ký tự dòng mới hoặc kết thúc bằng một ký tự dòng mới ngay trước ký tự dấu gạch chéo ngược trước khi xảy ra bất kỳ kết nối như vậy, sẽ được xử lý như thể một phần mới bổ sung ký tự dòng được thêm vào tệp (C ++ 11 §2.2 / 1).


28
Tất nhiên trong thực tế, mọi trình biên dịch đều thêm một dòng mới sau #include. Rất may.
mxcl

3
Tôi nhớ lại một phiên bản cũ của Microsoft Visual C ++ (như 2.x hoặc một cái gì đó) có chính xác vấn đề này. Nó đã trở nên trầm trọng hơn vì trình soạn thảo IDE khuyến khích loại hành vi thiếu dòng mới này.
Greg Hewgill

2
Trình biên dịch có thể không phàn nàn hiện tại, nhưng GitHub thực sự có.
Puyover

1
Tôi có thể thấy câu trả lời "bên dưới" của James nhưng: "Câu trả lời trên" trong OrderBy là gì?! Trên đây là câu hỏi, như tôi thường đặt hàng bằng phiếu bầu. Hay bạn có nghĩa là câu trả lời của riêng bạn?
mbx

@Thomas: Chương trình này có gọi hành vi không xác định vì nó không kết thúc với dòng mới. Xem chương trình tại đây: ideone.com/jswwf9
hủy diệt

44

Yêu cầu rằng mọi tệp nguồn kết thúc bằng một dòng mới không thoát được loại bỏ trong C ++ 11. Các đặc điểm kỹ thuật hiện đọc:

Một tệp nguồn không trống và không kết thúc bằng một ký tự dòng mới hoặc kết thúc bằng một ký tự dòng mới ngay trước ký tự dấu gạch chéo ngược trước khi xảy ra bất kỳ kết nối như vậy, sẽ được xử lý như thể một phần mới bổ sung ký tự dòng được thêm vào tệp (C ++ 11 §2.2 / 1).

Trình biên dịch tuân thủ sẽ không còn đưa ra cảnh báo này nữa (ít nhất là không khi biên dịch ở chế độ C ++ 11, nếu trình biên dịch có các chế độ cho các phiên bản khác nhau của đặc tả ngôn ngữ).


4
Đó là tất cả tốt và tốt cho C ++; thật không may, C vẫn nói đó là UB, ngay cả trong bản dự thảo mới nhất của tiêu chuẩn C1X sắp tới.
Adam Rosenfield

11
Câu hỏi này được gắn thẻ [c ++] chứ không phải [c].
James McNellis

3
Mặc dù vậy, nó có lẽ nên được gắn thẻ [c], vì nhiều người tìm kiếm cảnh báo này trong C sẽ tìm đường đến đây.
Adam Rosenfield

1
Đây vẫn là một điểm tốt để thêm. Thêm cái này lên trên. Hy vọng bạn không phiền.
TJ Seabrooks

25

Tiêu chuẩn C ++ 03 [2.1.1.2] tuyên bố:

... Nếu một tệp nguồn không trống không kết thúc bằng ký tự dòng mới hoặc kết thúc bằng ký tự dòng mới ngay trước ký tự dấu gạch chéo ngược trước khi xảy ra bất kỳ hoạt động nối nào như vậy, hành vi không được xác định.


16

Câu trả lời cho "vâng lời" là "bởi vì Tiêu chuẩn C ++ 03 nói rằng hành vi của một chương trình không kết thúc trong dòng mới là không xác định" (diễn giải).

Câu trả lời cho sự tò mò là ở đây: http://gcc.gnu.org/ml/gcc/2001-07/msg01120.html .


4
Ahh, "hành vi không xác định" yêu quý. Khi các ngôn ngữ khác thất bại, c / c ++ hành xử theo cách "không xác định" :) Điều đó, chắc chắn, là một phần lớn trong sự quyến rũ của họ. Và tôi không đùa.
shylent

6

Nó không đề cập đến một dòng trống, đó là liệu dòng cuối cùng (có thể có nội dung trong đó) được kết thúc bằng một dòng mới.

Hầu hết các trình soạn thảo văn bản sẽ đặt một dòng mới ở cuối dòng cuối cùng của tệp, vì vậy nếu dòng cuối cùng không có, có nguy cơ tệp bị cắt ngắn. Tuy nhiên, có những lý do hợp lệ tại sao bạn có thể không muốn dòng mới vì vậy nó chỉ là một cảnh báo, không phải là một lỗi.


5

#includesẽ thay thế dòng của nó bằng nội dung bằng chữ của tệp. Nếu tệp không kết thúc bằng một dòng mới, dòng chứa #includetệp được kéo vào sẽ hợp nhất với dòng tiếp theo.


2

Tôi đang sử dụng c-free IDE phiên bản 5.0, trong chương trình ngôn ngữ 'c ++' hoặc 'c' của tôi, tôi cũng gặp vấn đề tương tự. Ở cuối chương trình, tức là dòng cuối cùng của chương trình (sau khi kết thúc chức năng, nó có thể là chức năng chính hoặc bất kỳ), nhấn enter -line no. sẽ được tăng thêm 1. sau đó thực hiện cùng một chương trình, nó sẽ chạy mà không gặp lỗi.


2

Tất nhiên trong thực tế, mọi trình biên dịch đều thêm một dòng mới sau #include. Rất may. - @mxcl

không phải C / C ++ cụ thể mà là một phương ngữ C: khi sử dụng GL_ARB_shading_language_includephần mở rộng, trình biên dịch glsl trên OS X cảnh báo bạn KHÔNG về một dòng mới bị thiếu. Vì vậy, bạn có thể viết một MyHeader.htệp với một bảo vệ tiêu đề kết thúc bằng #endif // __MY_HEADER_H__và bạn sẽ mất dòng sau khi #include "MyHeader.h"chắc chắn.


2

Bởi vì hành vi khác nhau giữa các phiên bản C / C ++ nếu tệp không kết thúc bằng dòng mới. Đặc biệt khó chịu là C ++ cũ hơn - phiên bản, fx trong C ++ 03 tiêu chuẩn nói (giai đoạn dịch):

Nếu một tệp nguồn không trống không kết thúc bằng ký tự dòng mới hoặc kết thúc bằng ký tự dòng mới ngay trước ký tự dấu gạch chéo ngược, hành vi không được xác định.

Hành vi không xác định là xấu: trình biên dịch tuân thủ tiêu chuẩn có thể thực hiện ít nhiều những gì nó muốn ở đây (chèn mã độc hại hoặc bất cứ điều gì) - rõ ràng là một lý do để cảnh báo.

Mặc dù tình hình tốt hơn trong C ++ 11, một ý tưởng tốt là tránh các tình huống mà hành vi không được xác định trong các phiên bản trước. Đặc tả C ++ 03 kém hơn C99, hoàn toàn cấm các tệp đó (hành vi được xác định sau đó).


Tôi nghi ngờ Standard nói rằng các chương trình không có dòng mới có Hành vi không xác định, thay vì nói rằng chúng không được định dạng, bởi vì một số trình biên dịch sẽ nối một dòng cuối cùng không kết thúc của tệp được bao gồm với văn bản mã nguồn theo #includechỉ thị và một số lập trình viên nhắm mục tiêu các trình biên dịch như vậy có thể đã khai thác hành vi đó. Việc Tiêu chuẩn để lại những thứ như vậy Không xác định sẽ cho phép các chương trình khai thác các quirks đó được xác định rõ trên các nền tảng chỉ định hành vi đó. Có Tiêu chuẩn bắt buộc một hành vi sẽ phá vỡ các chương trình như vậy.
supercat

0

Cảnh báo này cũng có thể giúp chỉ ra rằng một tệp có thể đã bị cắt bớt bằng cách nào đó. Đúng là trình biên dịch có thể sẽ gây ra lỗi trình biên dịch - đặc biệt là nếu nó ở giữa hàm - hoặc có thể là lỗi liên kết, nhưng những lỗi này có thể khó hiểu hơn và không được đảm bảo xảy ra.

Tất nhiên, cảnh báo này cũng không được đảm bảo nếu tệp bị cắt ngay sau dòng mới, nhưng nó vẫn có thể bắt được một số trường hợp mà các lỗi khác có thể bỏ lỡ và đưa ra gợi ý mạnh hơn cho vấn đề.


-2

Đó không phải là một lỗi. Đó chỉ là một cảnh báo.

Mở tệp trong trình chỉnh sửa, đi đến dòng cuối cùng của tệp và nhấn enter để thêm một dòng trống vào cuối tệp.

Mặc dù, bên cạnh đó, bạn nên sử dụng #include <iostream>thay vì <iostream.h>. Sau đó đặt vào using std::cout;sau nó.

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.