Khi sử dụng tiêu đề C trong C ++, chúng ta nên sử dụng các hàm từ std :: hay không gian tên toàn cục?


113

C là một tập hợp con của C ++. Vì vậy, chúng ta có thể sử dụng hầu hết các hàm / tiêu đề C trong C ++ bằng cách thay đổi tên một chút ( stdio.hthànhcstdio , stdlib.hthành cstdlib).

Câu hỏi của tôi thực sự thuộc loại ngữ nghĩa. Trong mã C ++ (sử dụng phiên bản mới nhất của trình biên dịch GCC), tôi có thể gọiprintf("Hello world!");std::printf("Hello world!");và nó hoạt động hoàn toàn giống nhau. Và trong tài liệu tham khảo tôi đang sử dụng, nó cũng xuất hiện như std::printf("Hello world!");.

Câu hỏi của tôi là, nó có được ưu tiên sử dụng std::printf();trong C ++ không? Có sự khác biệt?


17
Trong trường hợp một ngày nào đó, họ yêu cầu việc đổ Cký hiệu thư viện vào không gian tên toàn cầu là bất hợp pháp, tôi thích sử dụng các std::phiên bản đủ điều kiện hơn. (Thêm vào đó, tôi ước họ đã biến nó thành bất hợp pháp).
Galik

3
@Galik: Đồng ý. Điều đó sẽ an toàn cho rất nhiều câu hỏi ngu ngốc về các vấn đề C khi sử dụng trình biên dịch C ++.
quá trung thực cho trang web này

7
Không có chuyện “chửa hoang một chút”. Hoặc C là một tập hợp con, hoặc không. Sự thật là không phải vậy . Đó là lý do tại sao tiêu đề C phải được sửa đổi để hoạt động trong C ++.
quá trung thực cho trang web này

2
"hầu như tất cả" là một biện pháp khá vô dụng khi nói về một tập hợp nhiều phần tử không đếm được. Bằng cách lập luận tương tự, bạn có thể liên hệ C và Java.
Daniel Jour

9
@sasauke không, nó không phải là một tập hợp con. C và C ++ chắc chắn chia sẻ một tập con, nhưng bản thân C không phải là một tập con của C ++.
The Paramagnetic Croissant,

Câu trả lời:


106

Từ Tiêu chuẩn C ++ 11 (mỏ nhấn mạnh):

D.5 Tiêu đề thư viện tiêu chuẩn C [depr.c.headers]

  1. Để tương thích với thư viện tiêu chuẩn C ...
  2. Mọi tiêu đề C, mỗi tiêu đề có tên là form name.h , hoạt động như thể mỗi tên được đặt trong không gian tên thư viện chuẩn bởi tiêu đề cname tương ứng được đặt trong phạm vi không gian tên chung . Không xác định được liệu các tên này có được khai báo hoặc xác định lần đầu trong phạm vi không gian tên (3.3.6) của std không gian tên hay không và sau đó được đưa vào phạm vi không gian tên chung bằng cách sử dụng khai báo rõ ràng (7.3.3).
  3. Ví dụ: Tiêu đề cung cấp một cách <cstdlib> chắc chắn các khai báo và định nghĩa của nó trong không gian tên std . Nó cũng có thể cung cấp những tên này trong không gian tên chung. Tiêu đề <stdlib.h> chắc chắn cung cấp các khai báo và định nghĩa giống nhau trong không gian tên chung , giống như trong Tiêu chuẩn C. Nó cũng có thể cung cấp những tên này trong không gian tên std.

Việc sử dụng tiêu đề «name.h» không được dùng nữa, chúng đã được xác định là ứng viên để xóa khỏi các bản sửa đổi trong tương lai.

Vì vậy, tôi khuyên bạn nên bao gồm các tiêu đề «cname» và sử dụng các khai báo và định nghĩa từ stdkhông gian tên.

Nếu bạn phải sử dụng tiêu đề «name.h» vì một số lý do (nó không được dùng nữa, xem ở trên), tôi khuyên bạn nên sử dụng các khai báo và định nghĩa từ không gian tên chung.

Nói cách khác: thích

#include <cstdio>

int main() {
    std::printf("Hello world\n");
}

kết thúc

#include <stdio.h>

int main() {
    printf("Hello world\n");
}

1
N3242 không phải là bất kỳ tiêu chuẩn C ++ nào. N3337 bản nháp với ít khác biệt nhất so với C ++ 11.
MM

3
Ngoài ra, hãy xem Tại sao <cstdlib> của Jonathan Wakely phức tạp hơn bạn có thể nghĩ từ các blog Mũ đỏ. Anh ấy trình bày chi tiết một số vấn đề từ quan điểm của người triển khai thư viện chuẩn C ++. Anh ấy cũng cung cấp một lịch sử quay trở lại C ++ 98.
jww

@sergej - Bạn có tình cờ biết cách xử lý C ++ 03 về chủ đề này không? Hoặc là nó bị bắn trúng hoặc bỏ lỡ điều gì sẽ xảy ra?
jww

5
<name.h> có thể không được dùng nữa, không có khả năng chúng sẽ sớm bị xóa. Hoàn toàn ngược lại, trên thực tế. Có một đề xuất để xóa nhãn không dùng nữa, hãy xem open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . "Cuối cùng, có vẻ như rõ ràng rằng các tiêu đề C sẽ được giữ lại bản chất mãi mãi, như là một lớp tương thích rất quan trọng với C và POSIX Nó có thể là giá trị undeprecating các tiêu đề, [..]."
Sjoerd

81

<cmeow>luôn cung cấp ::std::purrvà có thể cung cấp hoặc không ::purr.

<meow.h>luôn cung cấp ::purrvà có thể cung cấp hoặc không ::std::purr.

Sử dụng biểu mẫu được đảm bảo cung cấp bởi tiêu đề bạn đưa vào.


7
STL ngụy trang kém?
nwp

@nwp nope. (15 ký tự)
TC

@TC Thật không may, khi tôi đã thử trên trình biên dịch của mình, cả hai đều <cmeow>không <meow.h>cung cấp ::std::purrvà cũng không ::purrphải là lỗi bộ xử lý trước. Chỉ <cstdio>và / hoặc <stdio.h>cung cấp ::std::printfvà / hoặc ::printf. : P
LF

4
@LF Bạn có thể cần strcatsản xuất ::purr.
Lundin

8

Không, bạn vẫn ổn.

Các gốc ý là các <___.h>tiêu đề sẽ là phiên bản C mà đặt tất cả mọi thứ trong không gian tên toàn cầu, và <c___>tiêu đề sẽ là C ++ - phiên bản ified, mà nơi mọi thứ trong stdkhông gian tên.

Tuy nhiên, trên thực tế, các phiên bản C ++ cũng đưa mọi thứ vào không gian tên chung. Và không có sự đồng thuận rõ ràng rằng việc sử dụng các std::phiên bản là "điều đúng đắn phải làm".

Vì vậy, về cơ bản, hãy sử dụng cái nào bạn thích. Phổ biến nhất có lẽ là sử dụng các hàm thư viện chuẩn C trong không gian tên chung ( printfthay vì std::printf), nhưng không có nhiều lý do để coi cái này "tốt hơn" so với cái kia.


2
"Và không có sự đồng thuận rõ ràng rằng việc sử dụng các phiên bản std :: là" điều đúng đắn cần làm "." Uh, vâng, hoàn toàn có sự đồng thuận rằng đó là điều đúng đắn cần làm.
Miles Rout

4
Làm thế nào để xác định một cách khách quan liệu đã đạt được sự đồng thuận hay chưa?
Jeremy Friesner

9
@JeremyFriesner bạn đăng về nó trên SO và xem liệu bạn có nhận được những bình luận không đồng ý hay không. :)
jalf

1
@JeremyFriesner: Tiêu chuẩn này không đảm bảo các phiên bản tiêu đề C ++ đặt số nhận dạng trong không gian tên chung. Tiêu chuẩn này cũng không chấp nhận các phiên bản tiêu đề C. Điều đó có vẻ khá đồng thuận với tôi. ;-)
DevSolar

2
Sau đó, @DevSolar tra từ "đồng thuận" trong từ điển. Nó không phải về những gì tiêu chuẩn nói, mà là những gì các lập trình viên C ++ nói - và đặc biệt, những gì họ làm . Có một lý do mà theo nghĩa đen mỗi thư viện thực hiện tiêu chuẩn cung cấp các tiêu đề C, có C ++ header đặt mọi thứ trong không gian tên toàn cầu là tốt. :)
jalf

3

Sự khác biệt duy nhất ở đây là std::printf()bằng cách thêm std::độ phân giải phạm vi, bạn sẽ đảm bảo an toàn cho bản thân khỏi ai đó viết một hàm có cùng tên trong tương lai, điều này sẽ dẫn đến xung đột không gian tên. Cả hai cách sử dụng sẽ dẫn đến các lệnh gọi API hệ điều hành chính xác giống nhau (bạn có thể kiểm tra nó trong Linux bằng cách chạy strace your_program).

Tôi thấy rất khó có khả năng ai đó đặt tên cho một hàm như vậy, cũng như printf()một trong những hàm được sử dụng phổ biến nhất hiện có. Ngoài ra, trong C ++, iostreams được ưu tiên hơn các cuộc gọi đến các cstdiohàm như printf.


1
Ngược lại, tôi thấy nó khá có khả năng: printfbị hỏng nặng trong C ++ do không được gõ mạnh, việc thay thế nó bằng một phiên bản tốt hơn là điều khá tự nhiên.
Konrad Rudolph

1
@KonradRudolph Bạn có thể tìm thấy nó theo cách đó nếu bạn muốn, nhưng bạn đã nhầm; không có nghĩa là phải gõ mạnh và có nhiều vấn đề không thể giải quyết dễ dàng với việc gõ mạnh cần thiết. Đó là lý do tại sao nhiều giải pháp C ++ tương đương chậm hơn nhiều so với printf. Nếu bạn muốn thay thế nó bằng một phiên bản "tốt hơn", bạn đang phá vỡ hợp đồng giữa ngôn ngữ và lập trình viên, và đang ở trong tình trạng tội lỗi để bắt đầu.
Alice

1
@Alice Uhm, tôi không phá vỡ bất kỳ hợp đồng nào: std::printfkhác với mynamespace::printf, và C ++ rõ ràng cho phép tôi xác định các hàm của riêng mình mà tên của chúng phủ bóng các hàm bên trong std. Điều đó đơn giản là không cần bàn cãi. Đối với tuyên bố của bạn rằng printfhiệu quả vì gõ lỏng lẻo, điều đó tất nhiên cũng sai. printfthậm chí không đặc biệt hiệu quả, có nhiều triển khai hiệu quả hơn được đánh máy mạnh mẽ.
Konrad Rudolph

@KonradRudolph Hoàn toàn không chính xác; bạn đang phá vỡ hợp đồng, được viết trong tiêu chuẩn, printf mà không có bất kỳ bộ định lượng nào áp dụng rõ ràng cho một cấu trúc C. Việc bạn sử dụng một không gian tên, làm bí danh cho không gian tên chung, không phải là một ý kiến ​​hay. Điều đó đơn giản là không cần bàn cãi .
Alice

5
@Alice Bạn có thể vui lòng trích dẫn tiêu chuẩn về điều này không? Tôi không biết về bất kỳ xung quanh nào như vậy.
Konrad Rudolph

3

Từ tiêu chuẩn C ++ 11:

Mọi tiêu đề C, mỗi tiêu đề có tên là form name.h, hoạt động như thể mỗi tên được đặt trong không gian tên thư viện chuẩn bởi tiêu đề cname tương ứng được đặt trong phạm vi không gian tên chung. Không xác định được liệu các tên này có được khai báo hay định nghĩa lần đầu trong phạm vi không gian tên (3.3.6) của std không gian tên hay không và sau đó được đưa vào phạm vi không gian tên chung bằng cách sử dụng khai báo rõ ràng (7.3.3).

Vì vậy, nếu bạn sử dụng <cstdio>, bạn có thể chắc chắn rằng, nó printfsẽ nằm trong namespace std, và do đó không nằm trong không gian tên chung.
Sử dụng một không gian tên chung tạo ra xung đột về tên. Đây không phải là cách C ++.

Do đó, tôi đang sử dụng <cstdio>tiêu đề và khuyên bạn nên làm như vậy.


4
Mặc dù tôi ước nó hoạt động theo cách này, nhưng điều này không đúng. Nếu bạn bao gồm, <cstdio>bạn được đảm bảo rằng std :: printf sẽ tồn tại, nhưng không có gì đảm bảo từ tiêu chuẩn if :: printf cũng sẽ tồn tại hoặc sẽ không tồn tại. Trên thực tế, trong mọi trình biên dịch mà tôi từng nghe về :: printf đều được đưa vào vùng tên chung khi bạn đưa vào <cstdio>.
wjl

3

Từ thực tế của riêng tôi: sử dụng std::tiền tố. Nếu không một ngày nào đó abs sẽ cắn bạn rất đau trong trường hợp bạn sử dụng điểm nổi.

Không đủ điều kiện absđề cập đến chức năng được xác định inttrên một số nền tảng. Trên những người khác, nó là quá tải. Tuy nhiên std::absluôn trong tình trạng quá tải đối với tất cả các loại.


2

Chỉ sử dụng printfmà không std::có thể tạo ra một số xung đột tên và được nhiều nhà phát triển c ++ coi là một cách làm không tốt. Google là bạn của bạn trên trang này, nhưng đây là một số liên kết, hy vọng điều này sẽ giúp

Tại sao "sử dụng không gian tên std" được coi là hành vi xấu? http://www.cplusplus.com/forum/beginner/61121/


4
using namespace stdlà một thực hành xấu nhưng sử dụng printfmà không std::có định nghĩa thì không.
syntagma,

using namespace std;không phải là vấn đề của tôi ở đây. Tôi không bao giờ sử dụng nó. printf();std::printf();làm việc trong C ++ mà không cần using namespace std;Đó là lý do tại sao tôi đăng câu hỏi.
DeiDei

@REACHUS Không đồng ý. Không có sự khác biệt giữa hai kịch bản.
Konrad Rudolph

Tôi sẽ không bao giờ sử dụng std::printfnó cảm thấy chỉ đơn giản là kỳ quặc.
trenki

@KonradRudolph Tôi không nói có sự khác biệt, tôi chỉ bày tỏ ý kiến ​​của mình (xem câu trả lời của tôi để biết thêm cơ sở).
syntagma,

2

Trong stdio

Đây là phiên bản C ++ của tiêu đề Thư viện C Chuẩn @c stdio.h và nội dung của nó (hầu hết) giống với tiêu đề đó, nhưng tất cả đều được chứa trong không gian tên @c std (ngoại trừ các tên được định nghĩa là macro trong C).

Vì vậy, nó sẽ không tạo ra bất kỳ sự khác biệt nào.

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.