C++流与 C 风格 IO?

发布于 2024-10-22 04:21:12 字数 161 浏览 2 评论 0原文

当我为一个小型爱好项目编写一些 C++ 代码时,我注意到我正在使用 C 风格的操作来访问 IO(printffopen 等)。

在 C++ 项目中涉及 C 函数是否被认为是“不好的做法”?与 C 风格的 IO 访问相比,使用流有哪些优点?

I was coding some C++ for a small hobby project when I noticed that I'm using C-style operations to access IO (printf, fopen, etc.).

Is it considered "bad practice" to involve C functions in C++ projects? What are the advantages of using streams over C-style IO access?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

月依秋水 2024-10-29 04:21:12

这是一个热门话题。

有些人更喜欢使用 C++ IO,因为它们是类型安全的(对象的类型和格式字符串中指定的类型之间不能有分歧),并且与 C++ 编码方式的其余部分更自然地流动。

然而,也有关于 C IO 函数的争论(我个人最喜欢的)。其中一些是:

  • 它们更容易与本地化集成,因为要本地化的整个字符串不会分解为较小的字符串,并且通过某些实现,本地化程序可以重新排序插入值的顺序,将它们移动到字符串中,...
  • 您可以直接查看将要写入的文本的格式(这对于流运算符来说确实很难)。
  • 由于没有内联,并且只有 printf 函数的一个实例,因此生成的代码较小(这在嵌入式环境中可能很重要)。
  • 在某些实现中比 C++ 函数更快。

就我个人而言,我不认为在 C++ 代码中使用 C 流是一种不好的做法。 一些组织甚至建议使用它们而不是 C++溪流。我认为不好的风格是在同一个项目中使用两者。我认为一致性是关键。


正如其他人所指出的,在一个相对较大的项目中,您可能不会直接使用它们,但您会使用一组最适合您的编码标准和需求(本地化、类型安全、 ...)。您可以使用一个或另一个 IO 接口来实现这一更高级别的接口,但您可能只会使用一个。


编辑:添加一些有关与本地化相关的 printf 格式化函数系列的优点的信息。请注意,这些信息仅对某些实施有效。

您可以使用 %m$ 而不是 % 通过索引引用参数,而不是按顺序引用它们。这可用于对格式化字符串中的值重新排序。以下程序将在标准输出上写入 Hello World!

#include <stdio.h>
int main() {
    printf("%2$s %1$s\n", "World!", "Hello");
    return 0;
}

考虑翻译这段 C++ 代码:

if (nb_files_deleted == 1)
    stream << "One file ";
else
    stream << nb_file_deleted << " files ";
stream << removed from directory \"" << directory << "\"\n";

这真的很难。使用 printf (以及像 < code>gettext 来处理本地化),代码不与字符串混合。因此,我们可以将字符串传递给本地化团队,并且如果某些语言中有特殊情况,则不必更新代码(在某些语言中,如果对象计数为0,则使用复数形式,在其他语言中,有三种形式,一种是单数形式,一种是有两个宾语和一个复数形式时,...)。

printf (ngettext ("One file removed from directory \"%2$s\"",
                  "%1$d files removed from directory \"%2$s\"",
                  n),
        n, dir);

This is an heated topic.

Some people prefer to use the C++ IO since they are type-safe (you can't have divergence between the type of the object and the type specified in the format string), and flow more naturally with the rest of the C++ way of coding.

However, there is also arguments for C IO functions (my personal favorites). Some of them are:

  • They integrate more easily with localisation, as the whole string to localise is not broken up in smaller strings, and with some implementation the localizer can reorder the order of the inserted value, move them in the string, ...
  • You can directly see the format of the text that will be written (this can be really hard with stream operators).
  • As there is no inlining, and only one instance of the printf function, the generated code is smaller (this can be important in embedded environment).
  • Faster than C++ function in some implementation.

Personally, I wouldn't consider it bad practice to use C stream in C++ code. Some organisations even recommend to use them over C++ stream. What I would consider bad style is to use both in the same project. Consistency is the key here I think.


As other have noted, in a relatively large project, you would probably not use them directly, but you would use a set of wrapper function (or classes), that would best fit your coding standard, and your needs (localisation, type safety, ...). You can use one or the other IO interface to implement this higher level interface, but you'll probably only use one.


Edit: adding some information about the advantage of printf formatting function family relating to the localisation. Please note that those information are only valid for some implementation.

You can use %m$ instead of % to reference parameter by index instead of referencing them sequentially. This can be used to reorder values in the formatted string. The following program will write Hello World! on the standard output.

#include <stdio.h>
int main() {
    printf("%2$s %1$s\n", "World!", "Hello");
    return 0;
}

Consider translating this C++ code:

if (nb_files_deleted == 1)
    stream << "One file ";
else
    stream << nb_file_deleted << " files ";
stream << removed from directory \"" << directory << "\"\n";

This can be really hard. With printf (and a library like gettext to handle the localization), the code is not mixed with the string. We can thus pass the string to the localization team, and won't have to update the code if there are special case in some language (in some language, if count of object is 0, you use a plural form, in other language, there are three forms one for singular, one when there is two object and a plural form, ...).

printf (ngettext ("One file removed from directory \"%2$s\"",
                  "%1$d files removed from directory \"%2$s\"",
                  n),
        n, dir);
凉薄对峙 2024-10-29 04:21:12

相比,printf 和朋友们非常不安全,并且无法扩展,当然 fopen 和朋友们没有 RAII,这意味着除非您使用分析器证明您确实需要性能差异(您已经证明在您的平台和代码中存在这种差异),否则您必须是个白痴才能使用 printf

编辑:本地化是一件我没有考虑过的有趣的事情。我从未本地化过任何代码,也无法评论 printf 的相对本地化能力

printf and friends are hideously unsafe compared to <iostream>, and cannot be extended, plus of course fopen and friends have no RAII, which means that unless you've proved with a profiler that you definitely need the performance difference (that you've proved exists on your platform and in your code), you'd have to be an idiot to printf.

Edit: Localization is an interesting thing that I hadn't considered. I've never localized any code and cannot comment on the relative localizational ability of printf and <iostream>

楠木可依 2024-10-29 04:21:12

优点

  • 类型安全:C++流操作的参数类型在编译时检查,而printf参数通过...传递,导致未定义的行为如果它们与格式不匹配。
  • 资源管理:C++ 流对象具有析构函数来关闭文件句柄、释放缓冲区等。 C 流要求您记住调用 fclose

缺点

  • 性能:当然,这取决于实现,但我发现使用 C++ 流进行格式化比等效的 printf 格式化要慢得多。

Advantages

  • Type safety: the argument types of C++ streaming operations are checked at compile time, while printf arguments are passed through ... causing undefined behaviour if they do not match the formatting.
  • Resource management: C++ stream objects have destructors to close file handles, free buffers, and what have you. C streams require you to remember to call fclose.

Disadvantages

  • Performance: this depends on the implementation, of course, but I've found formatting with C++ streams to be considerably slower than the equivalent printf formatting.
过去的过去 2024-10-29 04:21:12

如果有明确的目的,任何事情都不能被视为不好的做法。我的意思是,如果 IO 是程序的瓶颈,那么是的,C 风格的 IO 比 C++ IO 的工作速度更快。但如果不是,我会采用 C++ 流方法。因为它更可爱:)

Nothing can be considered bad practice if it has a definite purpose. I mean, if IO is the bottleneck of the program, then yes, C-style IO works faster than C++ IO. But if it is not, I would go with C++ stream approach. Cuz it's cuter :)

何以笙箫默 2024-10-29 04:21:12

对于一个小型爱好项目,我可能会选择类型更安全的 C++ io 流。

有趣的是,我从未见过使用它们中任何一个的重要现实项目。在所有情况下,我们都使用了一些构建在本机操作系统 IO API 之上的抽象。

For a small hobby project I would probably go with the more type-safe C++ io streams.

Funny enough, I've never seen a non-trivial real-life project that uses either of them. In all cases we used some abstractions built on top of the native OS API for IO.

笨死的猪 2024-10-29 04:21:12

恕我直言,真正的 C++ 程序员会尝试以惯用的 C++ 方式做事;转为 C 语言的程序员试图坚持旧的做事方式。它与可读性和一致性有关。

IMHO, a real C++ programmer tries to do things in idiomatic C++ way; the C converted programmer tries to cling on old ways of doing things. It has to do with readability and consistency.

回首观望 2024-10-29 04:21:12

首先,您不必首先将 C++ 对象(尤其是 string)转换为 C 兼容形式。

For one, you don't have to convert C++ objects (notably strings) to C-compatible forms first.

苏辞 2024-10-29 04:21:12

<块引用>

在 C++ 项目中涉及 C 函数是否被认为是“不好的做法”?

通常,文件IO代码应该封装在类或函数实现中。我不认为您在封装实现中所做的任何选择是“不好的做法”,我保留该术语来表示影响库或代码(即接口)用户的因素。如果您在接口中公开文件 IO 机制,那么,IMO,无论您使用 IO 流还是 C 风格的 IO 函数,这都是不好的做法。

我宁愿说 C 风格的 IO 函数(可能总是)是更糟糕的选择。

<块引用>

与 C 风格的 IO 访问相比,使用流有哪些优点?

首先,它们与标准 C++ 结构(例如 std::string)更好地集成。它们与 STL 集成得相当好。它们允许您创建封装的自定义读/写运算符(<< 和 >>),以便您的自定义类在执行 IO 操作时几乎看起来像原始类型。

最后,C++中的IO流可以使用异常机制来报告流或读/写操作中的错误。这些通过避免可怕的错误代码机制(if 语句序列和丑陋的 while 循环,在每次操作后检查错误代码),使文件 IO 代码变得更好。

Is it considered "bad practice" to involve C functions in C++ projects?

Usually, the file IO code should be encapsulated in a class or function implementation. I wouldn't consider any choices you make in the encapsulated implementations to be "bad practice", I reserve that term for what affects the user of your library or code (i.e. the interface). If you are exposing your file IO mechanism in the interface, then, IMO, it's bad practice whether you use IO stream or C-style IO functions.

I would rather say that C-style IO functions are (probably always) the worse choice.

What are the advantages of using streams over C-style IO access?

First, they integrate better with standard C++ constructs such as std::string. They integrate fairly well with STL <algorithms>. And they allow you to create encapsulated custom read/write operators (<< and >>) such that your custom classes almost look like primitive types when it comes to doing IO operations.

Finally, IO streams in C++ can use exception mechanism to report errors in the stream or read/write operations. These make the file IO code much nicer by avoid the terrible look of error-code mechanisms (sequence of if-statements and ugly while-loops, that check the error code after each operation).

全部不再 2024-10-29 04:21:12

作为一般规则,您应该更喜欢 C++ 运算符,它们是:

-- 类型安全。您不必冒险传递双精度格式
需要一个 int。

——可扩展。您可以编写自己的插入器
提取器,并使用它们。

——可扩展。您可以定义自己的操纵器(使用
应用程序特定的逻辑含义),并使用它们。如果你
想要更改所有 WidgitNumber 的格式
(在内部,一个 int)在你的输出中,你改变
机械手;你不必找到所有的格式
语句,其中 %d 是 WidgitNumber。

——可扩展。您可以编写自己的接收器和源,并且
这些可以转发到其他接收器和源,进行过滤或
根据需要扩展输入或输出。

(FWIW:我认为我从未编写过这样的应用程序
没有使用自定义>>和<<操作员、自定义操纵器和
自定义streambuf。)

As a general rule, you should prefer C++ operators, they're:

-- Type safe. You don't risk passing a double where the format
calls for an int.

-- Extensible. You can write your own inserters and
extracters, and use them.

-- Extensible. You can define your own manipulators (with
application specific logical meaning), and use them. If you
want to change the format of all of the WidgitNumber
(internally, an int) in your output, you change the
manipulator; you don't have to find all of the format
statements where %d is a WidgitNumber.

-- Extensible. You can write your own sinks and sources, and
these can forward to other sinks and sources, filtering or
expanding the input or output as desired.

(FWIW: I don't think I've ever written an application which
didn't use custom >> and << operators, custom manipulators, and
custom streambuf's.)

风渺 2024-10-29 04:21:12

在 C++ 项目中涉及 C 函数是否被认为是“不好的做法”?

不。C 函数经常在 C++ 项目中使用。关于流,例如,Google C++ 样式指南建议仅在有限的情况下使用它们诸如“临时的、本地的、人类可读的、针对其他开发人员而不是最终用户”的情况。

与 C 风格的 IO 访问相比,使用流有哪些优点?

主要优点是类型安全性和可扩展性。然而 C++ 流有严重的缺陷,请参阅 这个问题的答案,例如本地化问题、糟糕的错误报告、代码膨胀和某些实现中的性能问题。

Is it considered "bad practice" to involve C functions in C++ projects?

No. C functions are often used in C++ projects. Regarding the streams, Google C++ Style Guide, for example, recommends using them only in limited cases such as "ad-hoc, local, human-readable, and targeted at other developers rather than end-users".

What are the advantages of using streams over C-style IO access?

The main advantages are type safety and extensibility. However C++ streams have serious flaws, see the answers to this question such as problems with localization, poor error reporting, code bloat and performance issues in some implementations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文