Question

Background:

In versions of Mac OS up to version 9, the standard representation for text files used an ASCII CR (carriage return) character, value decimal 13, to mark the end of a line.

Mac OS 10, unlike earlier releases, is UNIX-like, and uses the ASCII LF (line feed) character, value decimal 10, to mark the end of a line.

The question is, what are the values of the character constants '\n' and '\r' in C and C++ compilers for Mac OS releases prior to OS X?

There are (at least) two possible approaches that could have been taken:

  1. Treat '\n' as the ASCII LF character, and convert it to and from CR on output to and input from text streams (similar to the conversion between LF and CR-LF on Windows systems); or
  2. Treat '\n' as the ASCII CR character, which requires no conversion on input or output.

There would be some potential problems with the second approach. One is that code that assumes '\n' is LF could fail. (Such code is inherently non-portable anyway.) The other is that there still needs to be a distinct value for '\r', and on an ASCII-based system CR is the only sensible value. And the C standard doesn't permit '\n' == '\r' (thanks to mafso for finding the citation, 5.2.2 paragraph 3), so some other value would have to be used for '\r'.

What is the output of this C program when compiled and executed under Mac OS N, for N less than 10?

#include <stdio.h>
int main(void) {
    printf("'\\n' = %d\n", '\n');
    printf("'\\r' = %d\n", '\r');
    if ('\n' == '\r') {
        printf("Hmm, this could be a problem\n");
    }
}

The question applies to both C and C++. I presume the answer would be the same for both.

The answer could also vary from one C compiler to another -- but I would hope that compiler implementers would have maintained consistency with each other.

To be clear, I am not asking what representation old releases of Mac OS used to represent end-of-line in text files. My question is specifically and only about the values of the constants '\n' and '\r' in C or C++ source code. I'm aware that printing '\n' (whatever its value is) to a text stream causes it to be converted to the system's end-of-line representation (in this case, ASCII CR); that behavior is required by the C standard.

Was it helpful?

Solution

The values of the character constants \r and \n was the exact same in Classic Mac OS environments as it was everywhere else: \r was CR was ASCII 13 (0x0d); \n was LF was ASCII 10 (0x0a). The only thing that was different on Classic Mac OS was that \r was used as the "standard" line ending in text editors, just like \n is used on UNIX systems, or \r\n on DOS and Windows systems.

Here's a screenshot of a simple test program running in Metrowerks CodeWarrior on Mac OS 9, for instance:

Example program running in CodeWarrior

Keep in mind that Classic Mac OS systems didn't have a system-wide standard C library! Functions like printf() were only present as part of compiler-specific libraries like SIOUX for CodeWarrior, which implemented C standard I/O by writing output to a window with a text field in it. As such, some implementations of standard file I/O may have performed some automatic translation between \r and \n, which may be what you're thinking of. (Many Windows systems do similar things for \r\n if you don't pass the "b" flag to fopen(), for instance.) There was certainly nothing like that in the Mac OS Toolbox, though.

OTHER TIPS

I've done a search and found this page with an old discussion where especially the following can be found:

The Metrowerks MacOS implementation goes a step further by reversing the significance of CR and LF with regard to the '\r' and '\n' escapes in i/o involving a file, but not in any other context. This means that if you open a FILE or fstream in text mode, every '\r' will be output there as an LF as well as every '\n' being output as CR, and the same is true of input - the escape-to-ASCII-binary correspondences are reversed. They are not reversed however in memory, e.g. with sprintf() to a buffer or with a std::stringstream. I find this confusing and, if not non-standard, at least worse than other implementations.

It turns out there is a workaround with MSL - if you open the file in binary mode then '\n' always == LF and '\r' always == CR. This is what I wanted but in getting this information I also got a lot of justification from folks over there that this was the "standard" way to get what I wanted, when I feel like this is more like a workaround for a bug in their implementation. After all, CR and LF are 7-bit ASCII values and I'd expect to be able to use them in a standard way with a file opened in text mode.

(An answer makes clear that this is indeed not a violation of the standard.)

So obviously there was at least one implementation which used \n and \r with the usual ASCII values, but translated them in (non-binary) file output (by just exchanging them).

C-language specification:

5.2.2
...
2 Alphabetic escape sequences representing nongraphic characters in the execution character set are intended to produce actions on display devices as follows:
...
\n (new line) Moves the active position to the initial position of the next line.
\r (carriage return) Moves the active position to the initial position of the current line.

so \n represents the appropriate char in that character encoding... in ASCII is the LF char

I don't have an old Mac compiler to check if they follow this, but the numeric value of '\n' should be the same as the ASCII new line character (given that those compilers used ASCII compatible encoding as the execution encoding, which I believe they did). '\r' should have the same numeric value as the ASCII carriage return.

The library or OS functions that handle writing text mode files is responsible for converting the numeric value of '\n' to whatever the OS uses to terminate lines. The numeric values of these characters at runtime are determined entirely by the execution character set.

Thus, since we're still ASCII compatible execution encodings the numeric values should be the same as with classic Mac compilers.

On older Mac compilers, the roles of \r and \n where reversed: We had '\n' == 13 and '\r' == 10, while today '\n' == 10 and '\r' == 13. Great fun during the transition phase. Write a '\n' to a file with an old compiler, read the file with a new compiler, and get a '\r' (of course, both times you actually had a number 13).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top