2

How might one go about printing an em dash in C?

One of these: —

Whenever I do: printf("—") I just get a ù in the terminal.

Thank you.

EDIT: The following code is supposed to print out an Xs an Os looking grid with em dashes for the horizontal lines.

int main ()
{
    char grid[3][3] = {{'a', 'a', 'a'}, {'a', 'a', 'a'}, {'a', 'a', 'a'}};

    int i, j;

    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            if (j != 0)
            {
                printf("|");
            }
            printf("  %c  ", grid[i][j]);
        }
        if (i != 2)
        {
            printf("\n——————————————\n");
        }
    }

    return 0;
}

Output: (The "ù"s should be "—"s)

  a  |  a  |  a
ùùùùùùùùùùùù
  a  |  a  |  a
ùùùùùùùùùùùù
  a  |  a  |  a

EDIT: I'm on Windows 10 x64 using Codeblocks 16.01 with C11.

EDIT: I was informed of box characters and the question has morphed into how to print those, hence the title and tag change.

Elliot Killick
  • 389
  • 2
  • 4
  • 12
  • Take a look at https://stackoverflow.com/questions/10357622/whats-the-ascii-character-code-for – m0h4mm4d Aug 06 '17 at 15:25
  • 4
    em dash is not part of ASCII, and only if your compiler is C95 compliant you can use `wchar`. Also your terminal and OS should support it as well. – m0h4mm4d Aug 06 '17 at 15:26
  • Works on Linux with a UTF8 locale. – Petr Skocik Aug 06 '17 at 15:28
  • good tradition id to write sources in unicode numbers. Non ASCII sources can give late errors – Jacek Cz Aug 06 '17 at 15:31
  • Take a look at https://stackoverflow.com/q/15528359/2305521 – fpg1503 Aug 06 '17 at 15:32
  • Why not use dash (-) instead and avoid all these complications? Most text based softwares use it. – m0h4mm4d Aug 06 '17 at 15:39
  • 2
    You might as well use the [box drawing characters](https://en.wikipedia.org/wiki/Box-drawing_character) if you're going to use non-ascii characters to draw out those lines. Then at least it will look like the lines go together. – Jeff Mercado Aug 06 '17 at 15:56

1 Answers1

8

In standard C, you use wide characters and wide strings:

#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#include <wchar.h>

int main(void)
{
    setlocale(LC_ALL, "");
    fwide(stdout, 1);

    wprintf(L" \n");

    wprintf(L"   │   │   \n");
    wprintf(L"───┼───┼───\n");
    wprintf(L"   │   │   \n");
    wprintf(L"───┼───┼───\n");
    wprintf(L"   │   │   \n");

    return EXIT_SUCCESS;
}

You can use wide character constants like L'┼'; their conversion specifier for printf() and wprintf() functions is %lc. Similarly, a wide string constant has an L prefix, and its conversion specifier is %ls.

Unfortunately, you are limited to the mangled version of C Microsoft provides, so it may or may not work for you.


The above code does not work in Windows, because Microsoft does not want it to. See Microsoft documentation on setlocale() for details:

The set of available locale names, languages, country/region codes, and code pages includes all those supported by the Windows NLS API except code pages that require more than two bytes per character, such as UTF-7 and UTF-8.

In other words, Microsoft's C localization is limited to one-byte code pages, and specifically excludes any Unicode locales. This is, however, purely part of Microsoft's EEE strategy to bind you, a budding developer, to Microsoft's own walled garden, so that you will not write actual portable C code (or, horror of horrors, avail yourself to POSIX C), but are mentally locked to the Microsoft model. You see, you can use _setmode() to enable Unicode output.

As I do not use Windows at all myself, I cannot verify whether the following Windows-specific workarounds actually work or not, but it is worth trying. (Do report your findings in a comment, Windows users, please, so I can fix/include this part of this answer.)

#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#include <wchar.h>

#ifdef _WIN32
#include <io.h>
#include <fcntl.h>

static int set_wide_stream(FILE *stream)
{
    return _setmode(_fileno(stream), _O_U16TEXT);
}

#else

static int set_wide_stream(FILE *stream)
{
    return fwide(stream, 1);
}

#endif

int main(void)
{
    setlocale(LC_ALL, "");

    /* After this call, you must use wprintf(),
       fwprintf(), fputws(), putwc(), fputwc()
       -- i.e. only wide print/scan functions
       with this stream.
       You can print a narrow string using e.g.
       wprintf(L"%s\n", "Hello, world!");
    */
    set_wide_stream(stdout, 1);

    /* These may not work in Windows, because
       the code points are 0x1F785 .. 0x1F7AE
       and Windows is probably limited to
       Unicode 0x0000 .. 0xFFFF */
    wprintf(L" \n");

    /* These are from the Box Drawing Unicode block,
       U+2500 ─, U+2502 │, and U+253C ┼,
       and should work everywhere. */
    wprintf(L"   │   │   \n");
    wprintf(L"───┼───┼───\n");
    wprintf(L"   │   │   \n");
    wprintf(L"───┼───┼───\n");
    wprintf(L"   │   │   \n");

    return EXIT_SUCCESS;
}
Nominal Animal
  • 38,216
  • 5
  • 59
  • 86
  • Unfortunately, I was unable to get those box characters working. They just got turned into -, ¦ and +. Is this just a Windows thing? Is it possible to get the box characters displayed properly on Windows? Also, those characters don't work either. They just output to nothing in the command prompt. And also when you say "mangled version of C Microsoft provides" what exactly does that mean? Thank you and sorry for so many questions. – Elliot Killick Aug 07 '17 at 00:36
  • 1
    @Halp: I mean exactly what you found. It Just Works on other operating systems, you see: Microsoft is the one that wants it to not work. This *can* happen on any system where the character set used by the user's locale does not have those characters. It's just that because Windows specifically does *not* support Unicode (or any other multibyte character set) locales in C code, it happens in Windows regardless of your locale. Most users (across operating systems) in 2017 do use an Unicode locale. Could you try my blind-coded Windows-extended example? – Nominal Animal Aug 07 '17 at 10:20
  • I compiled the code and got an error on line 12: `error: '_O_U16TEXT' undeclared (first use in this function)|` and on line 35: `error: too many arguments to function 'set_wide_stream'|`. This last error is an easy fix, I just got rid of the second argument. And for the last error I was able to fix it by googling and finding this similar question regarding C++, but it seems to have worked for C too: https://stackoverflow.com/questions/10882277/properly-print-utf8-characters-in-windows-console I just did: `#define _O_U16TEXT 0x20000`. PT1 – Elliot Killick Aug 08 '17 at 15:35
  • Then I just took out `#include ` because it seemed to be unnecessary and it worked great! (Except for the Xs and Os characters for the reason you mentioned) Here's the final code: https://pastebin.com/yx3WL7XA. Here is the output: https://imgur.com/a/hDZxJ. Thank you for all your help. – Elliot Killick Aug 08 '17 at 15:44
  • And would you recommend me learning C in a Linux environment to get around all this nonsense? I did test the box characters on a Debian VM and it printed perfectly without all this extra code, just as you said it would. – Elliot Killick Aug 08 '17 at 15:48
  • 1
    @Halp: It depends on what do you want to do with your programming skills. If you intend to work on high-performance computing, or custom server software, or with embedded devices, learning POSIX C makes a lot of sense. If you intend to work on Windows applications, you get nothing out of POSIX. If you want to write portable GUI applications in C, look into GTK+. I personally dislike the idea of having my skills locked to a commercial product with a single capricious corporate owner, so to me, the answer is simple: POSIX all the way. – Nominal Animal Aug 08 '17 at 18:02
  • Thanks. Since that's the case I will definitely begin programming my C programs in a Linux environment. If only Linux operating systems had all the applications Windows did I would definitely switch to it full-time as well. But it's only a matter of time at this point. :) – Elliot Killick Aug 09 '17 at 00:57
  • 1
    @Halp: I installed my first Linux server with many users in 1998, and switched completely to Linux in 2003-2005 (don't recall the exact year anymore), on both desktops and laptops. I'm writing this on an HP EliteBook 820 that has only ever ran Linux. Other than games, I really, honestly, don't see what applications you could lack in Linux. While you might wish for commercial apps like Microsoft Office, Adobe Photoshop, and Adobe Illustrator, I find LibreOffice, Gimp, and Inkscape to work for my needs; plus, I can extend them if I want/need to. – Nominal Animal Aug 09 '17 at 13:22