Declare multibyte character array where bytes > 2 - c++

How can I declare a multibyte character array in which each is character is represented for 3 or 4 bytes?
I know I can do: char var[] = "AA"; which will write to memory 6161 and I can do wchar var[] = L"AA"; which will do 00610061. How can I declare a wider character array in C or C++?
Is there any other prefix like the L to instruct the compiler to do so?

Both C and C++ offer char32_t. In C char32_t is a typedef of/same type as uint_least32_t. In C++ char32_t has the same size, signedness, and alignment as std::uint_least32_t, but is a distinct type.
Both of them can be used like
char32_t string[] = U"some text";

You could try this, as long as you don't mind manually typing out each character:
int characters[3] = { 'h', 'e', 'y' };
You can also use a capital U in front of the string literal to get UTF-32:
char32_t characters[] = U"hey";

Your best bet when talking multi-byte character arrays is to use UTF8 encoding. That way all of the standard string library functions will continue to work, and ASCII representations remain the same.

Related

Chinese character too large for enclosing character literal type

I'm trying to assign the Chinese character 牛 as a char value in C++. On Xcode, I get the error:
"Character too large for enclosing character literal type."
When I use an online IDE like JDoodle or Browxy, I get the error:
"multi-character character constant."
It doesn't matter whether I use char, char16_t, char32_t or wchar_t, it won't work. I thought any Chinese character could at least fit into wchar_t, but this appears not to be the case. What can I do differently?
char letter = '牛';
char16_t character = '牛';
char32_t hanzi = '牛';
wchar_t word = '牛';
All of your character literals are standard chars. To get a wider type, you need to include the proper prefix on the literal:
char letter = '牛';
char16_t character = u'牛';
char32_t hanzi = U'牛';
wchar_t word = L'牛';

Is a c-style string containing only one char considered a string?

Is a c-style string containing only one char considered a string or would you call that construct a char?
Zero or more characters followed by a NUL-terminator is a C-style string. You can use the double quotation character notation to define a literal.
In C, an int that can fit into a char, such as '3' is a char.
Something like '34' is multicharacter literal.
A one element buffer is still technically a buffer. Forming a pointer to the start of it is not at all affected by how many items are in it.
So no, it's not a char. Furthermore, even the type system would differentiate char[1] from char.
It's also worth nothing that you may be surprised by what is a 1 character string. Because this one "a" has two characters in the buffer, not one. The only one character buffer that is a valid C-string is the empty string.
Is a c-style string containing only one char considered a string or
would you call that construct a char?
Indeed a C-Style string means a string i.e. it is quite different from a char data type. Since in C language, You don't have a dedicated built-in type to manipulate and represent string type like in C++ we have std::string hence once has to use character arrays (essentially null terminated) i.e. char str[SIZE] = "something" to represent character string type. On the other hand a single character is stored in char which is altogether different from char []. These two things are not same!
Example,
char str[] = "a"; // sizeof(str) will give 2 because presence of extra NULL character
char c = 'a'; // simply a single character

How to convert wstring into byte vector

Hi I have a few typedefs:
typedef unsigned char Byte;
typedef std::vector<Byte> ByteVector;
typedef std::wstring String;
I need to convert String into ByteVector, I have tried this:
String str = L"123";
ByteVector vect(str.begin(), str.end());
As a result vectror contains 3 elements: 1, 2, 3. However it is wstring so every charcter in this string is wide so my expected result would be: 0, 1, 0, 2, 0, 3.
Is there any standart way to do that or I need to write some custom function.
Byte const* p = reinterpret_cast<Byte const*>(&str[0]);
std::size_t size = str.size() * sizeof(str.front());
ByteVector vect(p, p+size);
What is your actual goal? If you just want to get the bytes representing the wchar_t objects, a fairly trivial conversion would do the trick although I wouldn't use just a cast to to unsigned char const* but rather an explicit conversion.
On the other hand, if you actually want to convert the std::wstring into a sequence encoded using e.g. UTF8 or UTF16 as is usually the case when dealing with characters, the conversion used for the encoding becomes significantly more complex. Probably the easiest approach to convert to an encoding is to use C's wcstombs():
std::vector<char> target(source.size() * 4);
size_t n = wcstombs(&target[0], &source[0], target.size());
The above fragment assumes that source isn't empty and that the last wchar_t in source is wchar_t(). The conversion uses C's global locale and assumes to convert whatever character encoding is set up there. There is also a version wcstombs_l() where you can specify the locale.
C++ has similar functionality but it is a bit harder to use in the std::codecvt<...> facet. I can provide an example if necessary.

Multi-Byte UTF-8 in Arrays in C++

I have been having trouble working with 3-byte Unicode UTF-8 characters in arrays. When they are in char arrays I get multi-character character constant and implicit constant conversion warnings, but when I use wchar_t arrays, wcout returns nothing at all. Because of the nature of the project, it must be an array and not a string. Below is an example of what I've been trying to do.
#include <iostream>
#include <string>
using namespace std;
int main()
{
wchar_t testing[40];
testing[0] = L'\u0B95';
testing[1] = L'\u0BA3';
testing[2] = L'\u0B82';
testing[3] = L'\0';
wcout << testing[0] << endl;
return 0;
}
Any suggestions? I'm working with OSX.
Since '\u0B95' requires 3 bytes, it is considered a multicharacter literal. A multicharacter literal has type int and an implementation-defined value. (Actually, I don't think gcc is correct to do this)
Putting the L prefix before the literal makes it have type wchar_t and has an implementation defined value (it maps to a value in the execution wide-character set which is an implementation defined superset of the basic execution wide-character set).
The C++11 standard provides us with some more Unicode aware types and literals. The additional types are char16_t and char32_t, whose values are the Unicode code-points that represent the character. They are analogous to UTF-16 and UTF-32 respectively.
Since you need character literals to store characters from the basic multilingual plane, you'll need a char16_t literal. This can be written as, for example, u'\u0B95'. You can therefore write your code as follows, with no warnings or errors:
char16_t testing[40];
testing[0] = u'\u0B95';
testing[1] = u'\u0BA3';
testing[2] = u'\u0B82';
testing[3] = u'\0';
Unfortunately, the I/O library does not play nicely with these new types.
If you do not truly require using character literals as above, you may make use of the new UTF-8 string literals:
const char* testing = u8"\u0B95\u0BA3\u0B82";
This will encode the characters as UTF-8.

how to convert char * to uchar16 in JNI C++

here's what I am trying to do:
typedef uint16_t uchar16_t;
uchar16_t buf[32];
// buf will contain timezone information like GMT-6, Eastern Daylight Time, etc
char * str = "Test";
for (int i = 0; i <= strlen(str); i++)
buf[i] = str[i];
I guess that's not correct since uchar16_t would contain 2 bytes and str contains 1 byte.
What is it that I am supposed to do ?
Strlen? buf[32]? Trying to destroy the universe?
You want to use a wstringstream.
std::wstringstream lols;
lols << "Test";
std::wstring cakes;
lols >> cakes;
Edit#Comment:
You shouldn't use strlen because any decent string system allows embedded zeros, and strlen is seriously slow. In addition, you didn't resize your buffer as needed, so if you had a string of size > 31 you would get a buffer overflow. In addition, you would have to (if you did dynamically size your buffer) manually free it afterwards. Both of these things are serious failings of the C string system. My example code makes your standard library writer do all the work and avoid all these problems for you.
That's actually OK if your string will always be ASCII. To do it correctly, the portable function is mbstowcs which assumes you're converting from the default locale or if you're on Windows then there's API functions that let you specify the source code page explicitly.
Your code will work, as long as str is ASCII; calling strlen() in the loop condition is probably a bad idea, though. It might be easier to just use swprintf() if it's available on your system:
uchar16_t buf[32];
char *str = "Test";
swprintf(buf, sizeof buf, "%s", str);
Have a look here.
Also, is there a good reason you are defining your own type?
If you have a (narrow) char string, you cannot convert it to
a wchar_t string by setting your locale to "C" and then passing
the string through mbstowcs(). That's because the "C" locale specifies
a -particular- character encoding, and that encoding might not match
the encoding of the execution character set, so mbstowcs() might
map the characters to something unexpected, or could even fail
(if the execution character set happened to use encodings that
were incompatible with the encoding structure for the C locale
character set.)
Thus, in order to convert a char
string into a wider string, you have
to copy the chars one by one into an
array of wchar_t . If you need to work
with Unicode or utf-16 or whatever
after that, then wcstombs() is what
you should look at.