Conversion of the cstring and char * types

Source: Internet
Author: User

CstringIs a useful data type. They greatly simplify many operations in MFC, making it much easier for MFC to perform string operations. In any case, there are many special skills to use cstring, especially for programmers coming out of the pure C background.

 

1. Convert cstring to char * (1 )--Forced type conversion to lpctstr

This is a slightly rigid conversion. First, we need to understand that cstring is a special C ++ object, which contains three values: A pointer to a data buffer, a valid string in the buffer, and a buffer length. The valid characters can be any number between 0 and the maximum buffer length minus 1 (because the string ends with a null character ). Characters and buffer length are cleverly hidden.
Unless you do some special operations, you cannot know the length of the buffer allocated to the cstring object. In this way, even if you have obtained the buffer address, you cannot change the content of the buffer, you cannot shorten the string, and you cannot lengthen the content of the buffer. Otherwise, you will see overflow immediately.
The lpctstr operator (or, more specifically, the tchar * operator) is overloaded in the cstring class. The definition of this operator is the return buffer address. Therefore, if you need a string pointer to cstring, you can do this:
Cstring S ("graycat ");
Lpctstr P = s;
It can run correctly. This is implemented by the mandatory type conversion rules in C language. When forced type conversion is required, C ++ allows this option. For example, you can define a floating point number as a number (with a pair of floating point numbers) to forcibly convert the type and return only the first floating point number (that is, the actual part) of the number ). It can be as follows:

Complex C (1.2f, 4.8f );
Float realpart = C;
If the (float) operator is correctly defined, the actual part value should be 1.2.
This type of forced conversion applies to all such cases. For example, any function with a parameter of the lpctstr type enforces this type of conversion. Therefore, you may have such a function (maybe in a DLL you bought ):

Bool dosomethingcool (lpctstr S );
You can call it as follows:

Cstring file ("C: \ myfiles \ coolstuff ")
Bool result = dosomethingcool (File );
It runs correctly. Because the dosomethingcool function has already stated that a parameter of the lpctstr type is required, therefore, the lpctstr is applied to this parameter, and the return string address is in MFC.

What if you want to format a string?

Cstring graycat ("graycat ");
Cstring S;
S. Format ("mew! I love % s ", graycat );
Note that the value in the Variable Parameter List (represented by "..." in the function description) does not imply a forced type conversion operator. What results do you get?
The actual result string we get is as follows:

"Mew! I love graycat ".
Because the MFC designers are very careful when designing the cstring data type, the cstring expression points to the string after the value is evaluated, so there is no forced type conversion like format or sprintf here, you can still get the correct behavior. The additional data describing cstring is actually after the cstring nominal address.
One thing you cannot do is modify the string. For example, you may try to replace "," with ". "(do not do this. If you care about internationalization, you should use the National Language Support feature of decimal conversion.) Below is a simple example:

Cstring V ("1.00"); // currency amount, two decimal places
Lpctstr P = V;
P [lstrlen (P)-3] = '','';
The compiler reports an error because you assign a constant string. If you try the following, the compiler will also be wrong:

Strcat (P, "each ");
Because the first parameter of strcat should be lptstr type data, but you have given it an lpctstr.

Do not try to drill down the tip of this error message. This will only put you into trouble!

The reason is that the buffer has a count, which is inaccessible (it is located in a hidden area under the cstring address). If you change this string, the character count in the buffer does not reflect the modification. In addition, if the length of a string happens to be the length of the physical limit of the string, expansion of the string will rewrite any data other than the buffer, that is, you do not have the permission to write the memory, you will destroy the memory that does not belong to you. This is the real death prescription for the app.

2. Convert cstring to char * (2)-- Use the getbuffer method of the cstring object

If you need to modify the content in cstring, there is a special method that can be used, that is, getbuffer, which is used to return a writable buffer pointer. If you only want to modify characters or truncate strings, you can do the following:

Cstring S (_ T ("file. Ext "));
Lptstr P = S. getbuffer ();
Lptstr dot = strchr (p, ''.''); // OK, shocould have used S. Find...
If (P! = NULL)
* P = _ T (''\ 0 '');
S. releasebuffer ();
This is the first usage of getbuffer and the simplest one. You do not need to pass a parameter to it. It uses the default value 0, which means: "Give me the pointer to this string, I promise not to lengthen it ". When you call releasebuffer, the actual length of the string is recalculated and then stored in the cstring object.
It must be emphasized that the range between getbuffer and releasebuffer must not use any method of the buffer cstring object you want to operate on. Because the integrity of the cstring object is not guaranteed before releasebuffer is called. Study the following code:

Cstring S (...);

Lptstr P = S. getbuffer ();

//... This pointer P has happened a lot

Int n = S. getlength (); // The answer may be incorrect.

S. trimright (); // cannot guarantee normal operation

S. releasebuffer (); // now it should be OK

Int M = S. getlength (); // The result is correct.

S. trimright (); // It will work normally.

If you want to increase the length of a string, you must first know how long the string may be, for example, when declaring a string array:

Char buffer [1024];
It indicates that the space of 1024 characters is sufficient for you to do anything you want. Representation of the same meaning in cstring:

Lptstr P = S. getbuffer (1024 );
After calling this function, you not only get the pointer to the string buffer, but also get a space of at least 1024 characters (note that I am talking about "character ", instead of "Byte", because cstring is implicitly aware of Unicode ).
At the same time, it should be noted that if you have a constant string pointer, the value of the string itself is stored in read-only memory. If you try to store it, even if you have already called getbuffer, and get a read-only memory pointer. The operation fails and an access error is reported. I didn't prove this on cstring, but I see that large C programmers often make this mistake.
A common problem for C programmers is to allocate a fixed-length buffer, perform sprintf operations on it, and assign it to a cstring:

Char buffer [256];
Sprintf (buffer, "%...", argS,...); // some omitted many details
Cstring S = buffer;
Although it is better to do this:

Cstring S;
S. Format (_ T ("%..."), argS ,...);
If your string length exceeds 256 characters, the stack will not be broken.

Another common error is that, since the fixed-size memory does not work, dynamic byte allocation is adopted, which has more disadvantages:

Int Len = lstrlen (parm1) + 13 lstrlen (parm2.) + 10 + 100;

Char * buffer = new char [Len];

Sprintf (buffer, "% s is equal to % s, valid data", parm1, parm2 );

Cstring S = buffer;

......

Delete [] buffer;
It can be simply written:

Cstring S;

S. Format (_ T ("% s is equal to % s, valid data"), parm1, parm2 );
Note that sprintf examples are not Unicode-ready. Although you can use tsprintf and use _ T () to enclose and format strings, the basic idea is still a detour, which is prone to errors.

3. cstring and temporary object

This is a small problem that occurs in the Microsoft. Public. VC. MFC News Group. I would like to mention that a programmer needs to write a string into the registry, and he writes:
I tried to use regsetvalueex () to set the value of a registry key, but its results are always confusing to me. It works normally when I declare a variable using char [], but when I use cstring, it always gets some garbage: "& yacute; & yacute ;... & yacute; "to confirm whether my cstring data is faulty, I tried to use getbuffer, then it is forcibly converted to char * And lpcstr. The value returned by getbuffer is correct, but when I assign it to char *, it turns into garbage. The following are my program segments:

Char * szname = getname (). getbuffer (20 );
Regsetvalueex (hkey, "name", 0, REG_SZ,
(Const byte *) szname,
Strlen (szname + 1 ));
The length of this name string is less than 20, so I don't think it is a problem with the getbuffer parameter.

This is confusing. Please help me.

Dear frustrated,

You have made a rather subtle mistake. The correct code should be like the following:

Cstring name = getname ();
Regsetvalueex (hkey, _ T ("name"), 0, REG_SZ,
(Const byte *) (lpctstr) Name,
(Name. getlength () + 1) * sizeof (tchar ));

Why is there a problem with the code I wrote? It is mainly because the cstring object returned when you call getname is a temporary object. See: C ++ Reference Manual § 12. 2
In some environments, it is necessary for the compiler to create a temporary object, so that the introduction of the temporary object is dependent on the implementation. If the class of the temporary object introduced by the compiler has constructor, the compiler must ensure that the constructor of this class is called. Similarly, if the class declaration has a destructor, make sure that the destructor of this temporary object is called.
The compiler must ensure that the temporary object is destroyed. The exact location of the destroyed object depends on the implementation... This destructor must be called before exiting the scope for creating the temporary object.
Most compilers are designed as follows: The next execution step of the Code created for the temporary object implicitly calls the destructor of the temporary object, which is generally implemented at the next semicolon. Therefore, this cstring object is parsed after the getbuffer call (by the way, you have no reason to pass a parameter to the getbuffer function, and it is not correct if releasebuffer is not used ). Therefore, getbuffer returns a pointer to the address of the string in the temporary object. However, when the temporary object is destructed, the memory is released. Then, the debug memory distributor of the MFC will fill in 0xdd for all the memory, and the "& yacute;" symbol is displayed. At this time, you write data to the registry, and the contents of the string are damaged.
We should not immediately convert this temporary object to the char * type. We should first save it to a cstring object, which means that a temporary object is copied, therefore, after the temporary cstring object is destructed, the value of this cstring object is still saved. At this time, it is no problem to write data to the Registry.
In addition, my code is Unicode-aware. The function that operates the registry requires a byte size. The actual result obtained using lstrlen (name + 1) is half the size of Unicode characters, and it cannot start from the second character of this string. Maybe your intention is lstrlen (name) + 1 (OK, I admit, I also made the same mistake !). In Unicode mode, all characters are 2 bytes in size. We need to solve this problem. Microsoft's document was surprised to say that the value of REG_SZ was calculated in bytes or in characters? Let's assume that it is measured in bytes. You need to make some modifications to your code to calculate the size of the byte contained in this string.

 

Reference recommendations:

Cstring (Baidu encyclopedia)

Conversion Between the cstring and char * types

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.