0

I tried to open a file in a non existing directory in C++ and for some reason my application didn't crash. I find that a bit "weird" because I'm used to C, where the equivalent program does crash. Here is my C++ version followed by the equivalent C version:

$ cat main.cpp
#include <fstream>
int main(int argc, char **argv)
{
    std::ofstream f("/home/oren/NON_EXISTING_DIR/file.txt");
    f << "lorem ipsum\n";
    f.close();
    printf("all good\n");
}
$ g++ main.cpp -o main
$ ./main
all good

When I try the equivalent thing with C I get a segfault:

$ cat main.c
#include <stdio.h>
int main(int argc, char **argv)
{
    FILE *fl = fopen("/home/oren/NON_EXISTING_DIR/file.txt","w+t");
    fprintf(fl,"lorem ipsum\n");
    fclose(fl);
    printf("all good\n");
}
$ gcc main.c -o main
$ ./main
Segmentation fault (core dumped)

Why is that?

OrenIshShalom
  • 5,974
  • 9
  • 37
  • 87
  • 6
    Your program crashes not because it failed to open a file but because it's dereferencing a null pointer. – melpomene Sep 15 '19 at 12:01
  • 3
    "Not crashing" doesn't mean "it works". – Andrew Henle Sep 15 '19 at 12:02
  • 1
    No program should crash when it attempts to open a nonexistent file. Attempting to open a nonexistent file is an ordinary failure mode that any file-opening program should handle gracefully. C programs must check the returned pointer after calling `fopen`, and not attempt to proceed if the pointer is NULL. C++ programs should do something similar. – Steve Summit Sep 15 '19 at 12:53

2 Answers2

3

"I'm used to C", but then "[...] in C++" - well, C++ is not C, but that's irrelevant here. First, have a look at this - writes to an unopened stream (which is the case here) are ignored after setting the failbit.

In your C example, however, the problem is that if fopen fais, it returns a NULL pointer. Then you pass it to fprintf. That's where the Undefined Behaviour1 happens. No such thing in the C++ example.


1Do note that the C example is not guaranteed to SEGFAULT. Undefined behaviour is undefined.

Fureeish
  • 12,533
  • 4
  • 32
  • 62
1

Documentation of used functions is the key. In both case program fails to open file. But concept of C++ library doesn't allow it to crash in constructor, for reasons. ofstream actually uses the same fopen or similar function. Let see what manual says:

Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer. Otherwise, NULL is returned and errno is set to indicate the error.

So you HAVE to check if returned value is NULL, otherwise you have an Undefined Behavior. ofstream does that for you, no undefined behavior happens during initialization of object.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42