C-style File Operations, C++ Streams, Exception Safety

  • Thread starter Scott Brady Drummonds
  • Start date
S

Scott Brady Drummonds

Hello, all,

My most recent assignment has me working on a medium- to large-sized
Windows-based C++ software project. My background is entirely on UNIX
systems, where it appears that most of my peers were writing "better" C++
code. By "better" I mean that it more regularly looked like C++ (use of
objects, streams, exceptions, and ANSI-compliance) whereas some of my recent
Windows-based C++ peers rely on un-portable, operating-system specific
methods. Also, there's a preponderance of C-style character/file operations
(sprintf(), fprintf(), etc.)

I've always believed in the C++ stream operations because I found them
intuitive and robust. My old team had also decided that mixing the two
stream operations was bad style and mandated that we stick to C++ streams.
I also have concerns about the operation of the C-style character operations
in the presence of exceptions. Given that they were written for C, they
probably are NOT exception-safe, right?

Is the use of C-style character/stream operations in our C++ project
something I should worry about? For those of you that are developing C++
code in Windows system, do you find that this free selection between these
two choices is prevalent? For what reasons should I or should I not worry
about this? What are recommended alternatives to generate the most
reliable, ANSI-compliant code on systems where C++-style streams are not
common?

Thanks!
Scott
 
D

Dietmar Kuehl

Scott said:
I also have concerns about the operation of the C-style character operations
in the presence of exceptions. Given that they were written for C, they
probably are NOT exception-safe, right?

Actually, it is quite likely that they *ARE* exception-safe:
Since they are written in C, they don't throw exceptions
themselves. On the other hand, you cannot inject C++
functionality into these functions which means that they cannot
throw an exception through user code either. That in turn means
that the C character and I/O functions actually have a no-throw
guarantee. That is, exception-safety is a non-issue with
respect to [most] C functions. The only exceptions are the
functions where you might pass in a C++ function, e.g.
'qsort()'. However, you don't want to call most of these anyway
(the one you might want to call is 'signal()' but registering a
function which throws is probably a pretty stupid idea).
Is the use of C-style character/stream operations in our C++ project
something I should worry about?

The C character functions are mostly unproblematic except that
you have to take care of passing only 'unsigned' integers to
them. This may or may not be automatically the case on your
system, depending whether 'char' is signed or unsigned. Of
course, if you want your code to be portable you need to cast
'char's before passing them to one of the ctype functions. The
only value with special treatment is 'EOF': this is typically a
negative value (usually '-1') and this value is treated
separately.

The primary problems with using C I/O functions:

- stdio is not extensible for I/O with user defined types.
- stdio is not extensible for new sources or destinations.
- stdio is not type-safe.
- You cannot register your own formatting routines with stdio.

The first three are, IMO, serious problems each of which making
stdio unsuitable for C++ projects. The forth issue depends on
your needs but is rarely a real issue.

There is, however, also a major issue with some imlementations
of IOStreams: a popular implementation at least had really bad
performance compared with stdio. Something like a factor of 10
was not that uncommon for typical file operations. This is
often a good reason to abandon IOStreams. However, AFAIK most
implementations now have comparable performance (but then, I
haven't made any measurements recently). That is, you might
want to verify that the performance of IOStreams is not
inferior to stdio performance. ~ou might want to accept a small
margin in return of the advantages but definitely no factor of
10.
 
J

Jesper Madsen

Dietmar Kuehl said:
Scott said:
I also have concerns about the operation of the C-style character operations
in the presence of exceptions. Given that they were written for C, they
probably are NOT exception-safe, right?

Actually, it is quite likely that they *ARE* exception-safe:
Since they are written in C, they don't throw exceptions
themselves. On the other hand, you cannot inject C++
functionality into these functions which means that they cannot
throw an exception through user code either. That in turn means
that the C character and I/O functions actually have a no-throw
guarantee. That is, exception-safety is a non-issue with
respect to [most] C functions. The only exceptions are the
functions where you might pass in a C++ function, e.g.
'qsort()'. However, you don't want to call most of these anyway
(the one you might want to call is 'signal()' but registering a
function which throws is probably a pretty stupid idea).

On windows you would probably get an exception from any function that can
result in a memory error,
e.g. sprintf(0,"something funky %s",0); And since you do not know the
implementation of the C standardlib, some a function allocating memory, and
calling another function could be non exception safe.

But there are more function that are not thread safe. Several standard C
routines use "global" or static data ptr as result. Or modifies a global
state...
 
D

Dietmar Kuehl

Jesper said:
On windows you would probably get an exception from any function that can
result in a memory error,
e.g. sprintf(0,"something funky %s",0);

This results in undefined behavior. Of course, undefined behavior is
bound to behave, well, undefined. This may include throwing exceptions,
of course. However, I assumed that the original question was about
well behaved code.
And since you do not know the
implementation of the C standardlib, some a function allocating memory, and
calling another function could be non exception safe.

I claim otherwise: according to the C specification, none of the C
function throws an exception. That is quite easy to see: there is
no such concept as exceptions in C. Thus, any function from the
standard C library which throws an exception [when being used
correctly and not invoking undefined behavior] is broken! The only
exception are functions parameterized by function where the parameter
effectively throws an exception (e.g. the compare function passed to
'qsort()'). However, none of the character or I/O functions falls
into this class.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top