I'm trying to write small program that reads in a character from an istream and converts it to a wchar_t. I'm getting a segfault. Here's my code
#include <iostream>
using namespace std;
wchar_t read(istream &stream) {
char *c;
stream.read(c, sizeof(*c));
cout << *c << endl;
wchar_t retChar = static_cast<wchar_t>(*c);
return retChar;
}
int main() {
cout << "Write something" << endl;
read(cin);
}
My logic here is:
Since I'm getting a segfault, there's obviously something wrong here. I can't see it though. Any help would be appreciated.
Thanks SO
Stepping through the code to give OP a look at what's going on and why it won't work. Then we'll take a look at a method to do what they want that is as close as possible to their intent. Then a hint on how to do this a bit better in the C++ world.
wchar_t read(istream &stream) {
char *c;
Declares a pointer c
and doesn't point it at anything. c
is an uninitialized variable. Think of it like being invited to Steve's house for a party, but no one told you where he lived. Odds are very good that where ever you go, it won't be Steve's house.
stream.read(c, sizeof(*c));
sizeof(*c)
will return the size of one character. Probably 8 bits and 1 byte, but c
still hasn't been pointed at anything so this is Undefined Behaviour. There is no telling what the program will do, but most likely it reads one byte into some unknown space in memory. Maybe this causes a crash because you can't write there. Maybe it writes over something that it is allowed to write over and screws up something else.
cout << *c << endl;
Tries to print out c
. If the program survived the read
above, odds are good it will survive this as well, but this is also Undefined Behaviour.
wchar_t retChar = static_cast<wchar_t>(*c);
This will literally stuff one character's worth of data into a wide character. It will not convert it according to locale or any other character encoding. char
is a numeric code that has been defined to be interpreted as a character. A cast will stupidly put the character value, say 'A' and ASCII encoding into retChar
. retChar
now equals 65. 65 could mean anything depending on the encoding used by wchar_t
. It might still mean 'A', but sorry Ayn Rand, this is one case where A may well not be A.
return retChar;
}
To do what OP was trying to do (and ignoring that there are better ways to do this for the time being):
#include <iostream>
using namespace std;
wchar_t read(istream &stream) {
char c[2];
Allocates an array of characters. Why? because the easiest way I know of is to do the conversion on a string.
stream.read(c, sizeof(c[0]));
c
is now an array which decays to a pointer. We only want to read one char
, so sizeof(c[0])
gets the size of the first element in the array.
c[1] = '\0';
cout << c << endl;
Null terminate and print.
wchar_t retChar[2];
Again, an array.
mbstowcs(retChar, c, 1);
convert one character from char to wide char using whatever locale has been set. Read more on locales here: http://en.cppreference.com/w/cpp/locale/setlocale
And documentation on mbstowcs: http://en.cppreference.com/w/cpp/string/multibyte/mbstowcs
return retChar[0];
}
Put all together with a quick tester:
#include <iostream>
#include <cstdlib>
wchar_t read(std::istream &stream)
{
char c[2];
stream.read(c, sizeof(c[0]));
c[1] = '\0';
std::cout << c << std::endl;
wchar_t retChar[2];
mbstowcs(retChar, c, 1);
return retChar[0];
}
int main()
{
std::wcout << read(std::cin) << std::endl;
}
This is simple, but ugly in the C++ world where you should stick to string
s where possible. In that case look into std::wstring_convert.