文章目录

  • 1、C语言库
    • 1.1 printf / scanf(C library)
    • 1.2 floor / ceil / round(C library)
    • 1.3 itoa / atoi (C library)
    • 1.4 sprintf(C library)
    • 1.5 sscanf(C library)
  • 2、C++标准库
    • 2.1 cin / cout(C++)
    • 2.1 std::stringstream(C++)
    • 2.2 std::to_string(C++11)
    • 2.3 std::stoi (C++11)
    • 2.4 std::format(C++20)
  • 3、Windows库
    • 3.1 从 char * 转换
    • 3.2 从 wchar_t * 转换
    • 3.3 从 _bstr_t 转换
    • 3.4 从 CComBSTR 转换
    • 3.5 从 CString 转换
    • 3.6 从 basic_string 转换
    • 3.7 从 System::String 转换
    • 3.8 WideCharToMultiByte
  • 4、boost库
  • 5、fmt库
    • 5.1 下载和编译
    • 5.2 测试代码
  • 结语


C++ 编译器支持情况表:

https://zh.cppreference.com/w/cpp/compiler_support#cpp17

std::format:

https://en.cppreference.com/w/cpp/utility/format/format
https://en.cppreference.com/w/cpp/string/basic_string/stol
https://cplusplus.com/reference/cstdio/

1、C语言库

1.1 printf / scanf(C library)

printf :将格式化数据打印到标准输出。
将格式所指向的 C 字符串写入标准输出(标准输出)。如果 format 包含格式说明符(以 % 开头的子序列),则格式后面的其他参数将被格式化并插入到结果字符串中,以替换它们各自的说明符。

int printf ( const char * format, ... );
/* printf example */
#include <stdio.h>int main()
{printf ("Characters: %c %c \n", 'a', 65);printf ("Decimals: %d %ld\n", 1977, 650000L);printf ("Preceding with blanks: %10d \n", 1977);printf ("Preceding with zeros: %010d \n", 1977);printf ("Some different radices: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);printf ("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);printf ("Width trick: %*d \n", 5, 10);printf ("%s \n", "A string");return 0;
}

scanf : 从 stdin 读取格式化数据
从 stdin 读取数据,并根据参数格式将它们存储到附加参数所指向的位置。
附加参数应指向格式字符串中由其相应的格式说明符指定的类型的已分配对象。

int scanf ( const char * format, ... );
/* scanf example */
#include <stdio.h>int main ()
{char str [80];int i;printf ("Enter your family name: ");scanf ("%79s",str);  printf ("Enter your age: ");scanf ("%d",&i);printf ("Mr. %s , %d years old.\n",str,i);printf ("Enter a hexadecimal number: ");scanf ("%x",&i);printf ("You have entered %#x (%d).\n",i,i);return 0;
}

1.2 floor / ceil / round(C library)

  • floor
    C 库函数 double floor(double x) 返回小于或等于 x 的最大的整数值。
    C头文件:#include<math.h>
    C++头文件:#include
#include <stdio.h>
#include <math.h>int main ()
{float val1, val2, val3, val4;val1 = 1.6;val2 = 1.2;val3 = 2.8;val4 = 2.3;printf("Value1 = %.1lf\n", floor(val1));printf("Value2 = %.1lf\n", floor(val2));printf("Value3 = %.1lf\n", floor(val3));printf("Value4 = %.1lf\n", floor(val4));return(0);
}
Value1 = 1.0
Value2 = 1.0
Value3 = 2.0
Value4 = 2.0
  • ceil
    C 库函数 double ceil(double x) 返回大于或等于 x 的最小的整数值。
    C头文件:#include<math.h>
    C++头文件:iostream
#include <stdio.h>
#include <math.h>int main ()
{float val1, val2, val3, val4;val1 = 1.6;val2 = 1.2;val3 = 2.8;val4 = 2.3;printf ("value1 = %.1lf\n", ceil(val1));printf ("value2 = %.1lf\n", ceil(val2));printf ("value3 = %.1lf\n", ceil(val3));printf ("value4 = %.1lf\n", ceil(val4));return(0);
}
value1 = 2.0
value2 = 2.0
value3 = 3.0
value4 = 3.0
  • round
    对于小数而言,round()函数仅仅保留到整数位,即仅仅对小数点后一位四舍五入。
    C头文件:#include<math.h>
    C++头文件:iostream
round(1.5)=2.000000
round(1.56)=2.000000
round(-1.5)=-2.000000
round(-1.56)=-2.000000

round()函数原理为:x=(int)(x+0.5)
可以自己写出round()函数如下:

#include<stdio.h>
double round(double x)
{return (int)(x+0.5);
}

1.3 itoa / atoi (C library)

此标头定义了几个通用函数,包括动态内存管理、随机数生成、与环境通信、整数算术、搜索、排序和转换。

头文件:cstdlib 和 stdlib.h

int atoi (const char * str);
char *  itoa ( int value, char * str, int base );

分析 C 字符串 str,将其内容解释为整数,该整数作为 int 类型的值返回。

/* atoi example */
#include <stdio.h>      /* printf, fgets */
#include <stdlib.h>     /* atoi */int main ()
{int i;char buffer[256];printf ("Enter a number: ");fgets (buffer, 256, stdin);i = atoi (buffer);printf ("The value entered is %d. Its double is %d.\n",i,i*2);return 0;
}
/* itoa example */
#include <stdio.h>
#include <stdlib.h>int main ()
{int i;char buffer [33];printf ("Enter a number: ");scanf ("%d",&i);itoa (i,buffer,10);printf ("decimal: %s\n",buffer);itoa (i,buffer,16);printf ("hexadecimal: %s\n",buffer);itoa (i,buffer,2);printf ("binary: %s\n",buffer);return 0;
}
Defined in header <stdlib.h> <cstdlib>
long      strtol( const char *str, char **str_end, int base );
long long strtoll( const char *str, char **str_end, int base );
#include <iostream>
#include <string>
#include <cerrno>
#include <cstdlib>
int main()
{const char* p = "111.11 -2.22 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz";char* end;std::cout << "Parsing \"" << p << "\":\n";for (double f = std::strtod(p, &end); p != end; f = std::strtod(p, &end)){std::cout << "'" << std::string(p, end-p) << "' -> ";p = end;if (errno == ERANGE){std::cout << "range error, got ";errno = 0;}std::cout << f << '\n';}
}

1.4 sprintf(C library)

Write formatted data to string

使用与 printf 上使用格式时将打印的文本相同的文本组成一个字符串,但内容不是打印,而是作为 C 字符串存储在 str 所指向的缓冲区中。

int sprintf ( char * str, const char * format, ... );sprintf(str,"%d",value) converts to decimal base.
sprintf(str,"%x",value) converts to hexadecimal base.
sprintf(str,"%o",value) converts to octal base.
sprintf(buf, "%d" , value);     用于转换带符号的整数
sprintf(buf, "%ld", value);     用于转换带符号的整数
sprintf(buf, "%lld",value);     用于转换带符号的整数
sprintf(buf, "%u",  value);     用于转换无符号整数
sprintf(buf, "%lu", value);     用于转换无符号整数
sprintf(buf, "%llu",value);     用于转换无符号整数
sprintf(buf, "%f",  value);     用于转换float、double
sprintf(buf, "%Lf", value);     用于转换long double
/* sprintf example */
#include <stdio.h>int main ()
{char buffer [50];int n, a=5, b=3;n=sprintf (buffer, "%d plus %d is %d", a, b, a+b);printf ("[%s] is a string %d chars long\n",buffer,n);return 0;
}

1.5 sscanf(C library)

Read formatted data from string

从 s 读取数据并根据参数格式将它们存储到附加参数给定的位置,就像使用了 scanf 一样,但从 s 而不是标准输入 (stdin) 读取数据。

int sscanf ( const char * s, const char * format, ...);
/* sscanf example */
#include <stdio.h>int main ()
{char sentence []="Rudolph is 12 years old";char str [20];int i;sscanf (sentence,"%s %*s %d",str,&i);printf ("%s -> %d\n",str,i);return 0;
}

2、C++标准库

2.1 cin / cout(C++)

Standard Input / Output Streams Library。

#include<iostream>
using namespace std;
int main(){int x;float y;cout<<"Please input an int number:"<<endl;cin>>x;cout<<"The int number is x= "<<x<<endl;cout<<"Please input a float number:"<<endl;cin>>y;cout<<"The float number is y= "<<y<<endl;   return 0;
}

2.1 std::stringstream(C++)

Input/output string stream.
Stream class to operate on strings.

此类的对象使用包含字符序列的字符串缓冲区。可以使用成员 str 将此字符序列作为字符串对象直接访问。

https://cplusplus.com/reference/sstream/stringstream/

// stringstream::str
#include <string>       // std::string
#include <iostream>     // std::cout
#include <sstream>      // std::stringstream, std::stringbufint main () {std::stringstream ss;ss.str ("Example string");std::string s = ss.str();std::cout << s << '\n';return 0;
}
#include <string>
#include <sstream>
#include <iostream>using namespace std;int main()
{stringstream sstream;// 将多个字符串放入 sstream 中sstream << "first" << " " << "string,";sstream << " second string";cout << "strResult is: " << sstream.str() << endl;// 清空 sstreamsstream.str("");sstream << "third string";cout << "After clear, strResult is: " << sstream.str() << endl;return 0;
}

2.2 std::to_string(C++11)

#include<string>
string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);

// to_string example
#include <iostream>   // std::cout
#include <string>     // std::string, std::to_stringint main ()
{std::string pi = "pi is " + std::to_string(3.1415926);std::string perfect = std::to_string(1+2+4+7+14) + " is a perfect number";std::cout << pi << '\n';std::cout << perfect << '\n';return 0;
}
// to_wstring example
#include <iostream>   // std::wcout
#include <string>     // std::wstring, std::to_wstringint main ()
{std::wstring pi = L"pi is " + std::to_wstring(3.1415926);std::wstring perfect = std::to_wstring(1+2+4+7+14) + L" is a perfect number";std::wcout << pi << L'\n';std::wcout << perfect << L'\n';return 0;
}

2.3 std::stoi (C++11)

https://cplusplus.com/reference/string/stoi/
https://en.cppreference.com/w/cpp/string/basic_string/stol

// string转为整数
int       stoi( const std::string& str, std::size_t* pos = 0, int base = 10 );
int       stoi( const std::wstring& str, std::size_t* pos = 0, int base = 10 );
long      stol( const std::string& str, std::size_t* pos = 0, int base = 10 );
long      stol( const std::wstring& str, std::size_t* pos = 0, int base = 10 );
long long stoll( const std::string& str, std::size_t* pos = 0, int base = 10 );
long long stoll( const std::wstring& str, std::size_t* pos = 0, int base = 10 );//string转为无符号long
unsigned long     stoul( const std::string& str, std::size_t* pos = 0, int base = 10 );
unsigned long     stoul( const std::wstring& str, std::size_t* pos = 0, int base = 10 );
unsigned long long stoull( const std::string& str, std::size_t* pos = 0, int base = 10 );
unsigned long long stoull( const std::wstring& str, std::size_t* pos = 0, int base = 10 );//string转为浮点型
float       stof( const std::string& str, std::size_t* pos = 0 );
float       stof( const std::wstring& str, std::size_t* pos = 0 );
double      stod( const std::string& str, std::size_t* pos = 0 );
double      stod( const std::wstring& str, std::size_t* pos = 0 );
long double stold( const std::string& str, std::size_t* pos = 0 );
long double stold( const std::wstring& str, std::size_t* pos = 0 );
#include <string>
#include <iomanip>
#include <utility>
#include <iostream>
#include <stdexcept>int main()
{const auto data = {"45","+45"," -45","3.14159","31337 with words","words and 2","12345678901",};for (const std::string s : data){std::size_t pos{};try{std::cout << "std::stoi('" << s << "'): ";const int i {std::stoi(s, &pos)};std::cout << i << "; pos: " << pos << '\n';}catch(std::invalid_argument const& ex){std::cout << "std::invalid_argument::what(): " << ex.what() << '\n';}catch(std::out_of_range const& ex){std::cout << "std::out_of_range::what(): " << ex.what() << '\n';const long long ll {std::stoll(s, &pos)};std::cout << "std::stoll('" << s << "'): " << ll << "; pos: " << pos << '\n';}}std::cout << "\nCalling with different radixes:\n";for (const auto& [s, base]: { std::pair<const char*, int>{"11",  2}, {"22",  3}, {"33",  4}, {"77",  8},{"99", 10}, {"FF", 16}, {"jJ", 20}, {"Zz", 36}, }){const int i {std::stoi(s, nullptr, base)};std::cout << "std::stoi('" << s << "', " << base << "): " << i << '\n';}
}

2.4 std::format(C++20)


根据格式字符串 fmt 格式化参数,并将结果写入输出迭代器。最多写 n 个字符。如果存在,则 loc 用于特定于区域设置的格式设置。

#include <format>
#include <iostream>
#include <string_view>int main()
{char buffer[64];const auto result =std::format_to_n(buffer, std::size(buffer) - 1, "Hubble's H{2} {3} {0}{4}{1} km/sec/Mpc.",71,       // {0}, occupies 2 bytes8,        // {1}, occupies 1 byte"\u2080", // {2}, occupies 3 bytes"\u2245", // {3}, occupies 3 bytes"\u00B1"  // {4}, occupies 2 bytes);*result.out = '\0';const std::string_view str{buffer, result.out}; // uses C++20 ctorstd::cout << "Buffer: \"" << str << "\"\n"<< "Buffer size = " << std::size(buffer) << '\n'<< "Untruncated output size = " << result.size << '\n';
}
  • Output:
Buffer: "Hubble's H₀ ≅ 71±8 km/sec/Mpc."
Buffer size = 64
Untruncated output size = 35

#include <format>
#include <iostream>
#include <iterator>
#include <string>auto main() -> int
{std::string buffer;std::format_to(std::back_inserter(buffer), //< OutputIt"Hello, C++{}!\n",          //< fmt "20");                      //< argstd::cout << buffer;buffer.clear();std::format_to(std::back_inserter(buffer), //< OutputIt"Hello, {0}::{1}!{2}",      //< fmt "std",                      //< arg {0}"format_to()",              //< arg {1}"\n",                       //< arg {2}"extra param(s)...");       //< unusedstd::cout << buffer;std::wstring wbuffer;std::format_to(std::back_inserter(wbuffer),//< OutputIt L"Hello, {2}::{1}!{0}",     //< fmtL"\n",                      //< arg {0}L"format_to()",             //< arg {1}L"std",                     //< arg {2}L"...is not..."             //< unusedL"...an error!");           //< unusedstd::wcout << wbuffer;
}
  • Output:
Hello, C++20!
Hello, std::format_to()!
Hello, std::format_to()!

#include <format>
#include <iostream>
#include <string_view>int main()
{char buffer[64];const auto result =std::format_to_n(buffer, std::size(buffer) - 1, "Hubble's H{2} {3} {0}{4}{1} km/sec/Mpc.",71,       // {0}, occupies 2 bytes8,        // {1}, occupies 1 byte"\u2080", // {2}, occupies 3 bytes"\u2245", // {3}, occupies 3 bytes"\u00B1"  // {4}, occupies 2 bytes);*result.out = '\0';const std::string_view str{buffer, result.out}; // uses C++20 ctorstd::cout << "Buffer: \"" << str << "\"\n"<< "Buffer size = " << std::size(buffer) << '\n'<< "Untruncated output size = " << result.size << '\n';
}
  • Output:
Buffer: "Hubble's H₀ ≅ 71±8 km/sec/Mpc."
Buffer size = 64
Untruncated output size = 35

3、Windows库

本文介绍如何将各种 Visual C++ 字符串类型转换为其他字符串。

涵盖的字符串类型包括 char 、wchar_t、_bstr_t、CComBSTR、CString、basic_string 和 System.String。

在所有情况下,当转换为新类型时,将创建字符串的副本。 对新字符串所做的任何更改都不会影响原始字符串,反之亦然。

3.1 从 char * 转换

char * 字符串(也称为 C 样式字符串)使用终止 null 来指示字符串的结尾。 C 样式字符串通常需要每个字符使用 1 个字节,但也可以使用 2 个字节。 在下面的示例中,char * 字符串有时被称为多字节字符串,因为字符串数据是从宽 Unicode 字符串转换而来的。 单字节和多字节字符 (MBCS) 函数可以对 char * 字符串进行操作。

// convert_from_char.cpp
// compile with: /clr /Zc:twoPhase- /link comsuppw.lib#include <iostream>
#include <stdlib.h>
#include <string>#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"using namespace std;
using namespace System;int main()
{// Create and display a C-style string, and then use it// to create different kinds of strings.const char* orig = "Hello, World!";cout << orig << " (char *)" << endl;// newsize describes the length of the// wchar_t string called wcstring in terms of the number// of wide characters, not the number of bytes.size_t newsize = strlen(orig) + 1;// The following creates a buffer large enough to contain// the exact number of characters in the original string// in the new format. If you want to add more characters// to the end of the string, increase the value of newsize// to increase the size of the buffer.wchar_t* wcstring = new wchar_t[newsize];// Convert char* string to a wchar_t* string.size_t convertedChars = 0;mbstowcs_s(&convertedChars, wcstring, newsize, orig, _TRUNCATE);// Display the result and indicate the type of string that it is.wcout << wcstring << L" (wchar_t *)" << endl;delete []wcstring;// Convert the C-style string to a _bstr_t string._bstr_t bstrt(orig);// Append the type of string to the new string// and then display the result.bstrt += " (_bstr_t)";cout << bstrt << endl;// Convert the C-style string to a CComBSTR string.CComBSTR ccombstr(orig);if (ccombstr.Append(L" (CComBSTR)") == S_OK){CW2A printstr(ccombstr);cout << printstr << endl;}// Convert the C-style string to a CStringA and display it.CStringA cstringa(orig);cstringa += " (CStringA)";cout << cstringa << endl;// Convert the C-style string to a CStringW and display it.CStringW cstring(orig);cstring += " (CStringW)";// To display a CStringW correctly, use wcout and cast cstring// to (LPCTSTR).wcout << (LPCTSTR)cstring << endl;// Convert the C-style string to a basic_string and display it.string basicstring(orig);basicstring += " (basic_string)";cout << basicstring << endl;// Convert the C-style string to a System::String and display it.String^ systemstring = gcnew String(orig);systemstring += " (System::String)";Console::WriteLine("{0}", systemstring);delete systemstring;
}

3.2 从 wchar_t * 转换

一些字符串类型(包括 wchar_t *)实现了宽字符格式。 若要在多字节和宽字符格式之间转换字符串,可以使用像 mbstowcs_s 这样的单个函数调用或像 CStringA 这样的类的构造函数调用。

// convert_from_wchar_t.cpp
// compile with: /clr /Zc:twoPhase- /link comsuppw.lib#include <iostream>
#include <stdlib.h>
#include <string>#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"using namespace std;
using namespace System;int main()
{// Create a string of wide characters, display it, and then// use this string to create other types of strings.const wchar_t* orig = L"Hello, World!";wcout << orig << L" (wchar_t *)" << endl;// Convert the wchar_t string to a char* string. Record// the length of the original string and add 1 to it to// account for the terminating null character.size_t origsize = wcslen(orig) + 1;size_t convertedChars = 0;// Use a multibyte string to append the type of string// to the new string before displaying the result.char strConcat[] = " (char *)";size_t strConcatsize = (strlen(strConcat) + 1) * 2;// Allocate two bytes in the multibyte output string for every wide// character in the input string (including a wide character// null). Because a multibyte character can be one or two bytes,// you should allot two bytes for each character. Having extra// space for the new string isn't an error, but having// insufficient space is a potential security problem.const size_t newsize = origsize * 2;// The new string will contain a converted copy of the original// string plus the type of string appended to it.char* nstring = new char[newsize + strConcatsize];// Put a copy of the converted string into nstringwcstombs_s(&convertedChars, nstring, newsize, orig, _TRUNCATE);// append the type of string to the new string._mbscat_s((unsigned char*)nstring, newsize + strConcatsize, (unsigned char*)strConcat);// Display the result.cout << nstring << endl;delete []nstring;// Convert a wchar_t to a _bstr_t string and display it._bstr_t bstrt(orig);bstrt += " (_bstr_t)";cout << bstrt << endl;// Convert the wchar_t string to a BSTR wide character string// by using the ATL CComBSTR wrapper class for BSTR strings.// Then display the result.CComBSTR ccombstr(orig);if (ccombstr.Append(L" (CComBSTR)") == S_OK){// CW2A converts the string in ccombstr to a multibyte// string in printstr, used here for display output.CW2A printstr(ccombstr);cout << printstr << endl;// The following line of code is an easier way to// display wide character strings:wcout << (LPCTSTR)ccombstr << endl;}// Convert a wide wchar_t string to a multibyte CStringA,// append the type of string to it, and display the result.CStringA cstringa(orig);cstringa += " (CStringA)";cout << cstringa << endl;// Convert a wide character wchar_t string to a wide// character CStringW string and append the type of string to itCStringW cstring(orig);cstring += " (CStringW)";// To display a CStringW correctly, use wcout and cast cstring// to (LPCTSTR).wcout << (LPCTSTR)cstring << endl;// Convert the wide character wchar_t string to a// basic_string, append the type of string to it, and// display the result.wstring basicstring(orig);basicstring += L" (basic_string)";wcout << basicstring << endl;// Convert a wide character wchar_t string to a// System::String string, append the type of string to it,// and display the result.String^ systemstring = gcnew String(orig);systemstring += " (System::String)";Console::WriteLine("{0}", systemstring);delete systemstring;
}

3.3 从 _bstr_t 转换

_bstr_t 对象封装宽字符 BSTR 字符串。 BSTR 字符串具有长度值,并且不使用 null 字符终止字符串,但要转换为的字符串类型可能需要终止 null 字符。

// convert_from_bstr_t.cpp
// compile with: /clr /Zc:twoPhase- /link comsuppw.lib#include <iostream>
#include <stdlib.h>
#include <string>#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"using namespace std;
using namespace System;int main()
{// Create a _bstr_t string, display the result, and indicate the// type of string that it is._bstr_t orig("Hello, World!");wcout << orig << " (_bstr_t)" << endl;// Convert the wide character _bstr_t string to a C-style// string. To be safe, allocate two bytes for each character// in the char* string, including the terminating null.const size_t newsize = (orig.length() + 1) * 2;char* nstring = new char[newsize];// Uses the _bstr_t operator (char *) to obtain a null// terminated string from the _bstr_t object for// nstring.strcpy_s(nstring, newsize, (char*)orig);strcat_s(nstring, newsize, " (char *)");cout << nstring << endl;delete []nstring;// Prepare the type of string to append to the result.wchar_t strConcat[] = L" (wchar_t *)";size_t strConcatLen = wcslen(strConcat) + 1;// Convert a _bstr_t to a wchar_t* string.const size_t widesize = orig.length() + strConcatLen;wchar_t* wcstring = new wchar_t[newsize];wcscpy_s(wcstring, widesize, (wchar_t*)orig);wcscat_s(wcstring, widesize, strConcat);wcout << wcstring << endl;delete []wcstring;// Convert a _bstr_t string to a CComBSTR string.CComBSTR ccombstr((char*)orig);if (ccombstr.Append(L" (CComBSTR)") == S_OK){CW2A printstr(ccombstr);cout << printstr << endl;}// Convert a _bstr_t to a CStringA string.CStringA cstringa(orig.GetBSTR());cstringa += " (CStringA)";cout << cstringa << endl;// Convert a _bstr_t to a CStringW string.CStringW cstring(orig.GetBSTR());cstring += " (CStringW)";// To display a cstring correctly, use wcout and// "cast" the cstring to (LPCTSTR).wcout << (LPCTSTR)cstring << endl;// Convert the _bstr_t to a basic_string.string basicstring((char*)orig);basicstring += " (basic_string)";cout << basicstring << endl;// Convert the _bstr_t to a System::String.String^ systemstring = gcnew String((char*)orig);systemstring += " (System::String)";Console::WriteLine("{0}", systemstring);delete systemstring;
}

3.4 从 CComBSTR 转换

与 _bstr_t 一样,CComBSTR 对象封装宽字符 BSTR 字符串。 BSTR 字符串具有长度值,并且不使用 null 字符终止字符串,但要转换为的字符串类型可能需要终止 null。

// convert_from_ccombstr.cpp
// compile with: /clr /Zc:twoPhase- /link comsuppw.lib#include <iostream>
#include <stdlib.h>
#include <string>#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"
#include "vcclr.h"using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;int main()
{// Create and initialize a BSTR string by using a CComBSTR object.CComBSTR orig("Hello, World!");// Convert the BSTR into a multibyte string, display the result,// and indicate the type of string that it is.CW2A printstr(orig);cout << printstr << " (CComBSTR)" << endl;// Convert a wide character CComBSTR string to a// regular multibyte char* string. Allocate enough space// in the new string for the largest possible result,// including space for a terminating null.const size_t newsize = (orig.Length() + 1) * 2;char* nstring = new char[newsize];// Create a string conversion object, copy the result to// the new char* string, and display the result.CW2A tmpstr1(orig);strcpy_s(nstring, newsize, tmpstr1);cout << nstring << " (char *)" << endl;delete []nstring;// Prepare the type of string to append to the result.wchar_t strConcat[] = L" (wchar_t *)";size_t strConcatLen = wcslen(strConcat) + 1;// Convert a wide character CComBSTR string to a wchar_t*.// The code first determines the length of the converted string// plus the length of the appended type of string, then// prepares the final wchar_t string for display.const size_t widesize = orig.Length() + strConcatLen;wchar_t* wcstring = new wchar_t[widesize];wcscpy_s(wcstring, widesize, orig);wcscat_s(wcstring, widesize, strConcat);// Display the result. Unlike CStringW, a wchar_t doesn't need// a cast to (LPCTSTR) with wcout.wcout << wcstring << endl;delete []wcstring;// Convert a wide character CComBSTR to a wide character _bstr_t,// append the type of string to it, and display the result._bstr_t bstrt(orig);bstrt += " (_bstr_t)";cout << bstrt << endl;// Convert a wide character CComBSTR to a multibyte CStringA,// append the type of string to it, and display the result.CStringA cstringa(orig);cstringa += " (CStringA)";cout << cstringa << endl;// Convert a wide character CComBSTR to a wide character CStringW.CStringW cstring(orig);cstring += " (CStringW)";// To display a cstring correctly, use wcout and cast cstring// to (LPCTSTR).wcout << (LPCTSTR)cstring << endl;// Convert a wide character CComBSTR to a wide character// basic_string.wstring basicstring(orig);basicstring += L" (basic_string)";wcout << basicstring << endl;// Convert a wide character CComBSTR to a System::String.String^ systemstring = gcnew String(orig);systemstring += " (System::String)";Console::WriteLine("{0}", systemstring);delete systemstring;
}

3.5 从 CString 转换

CString 基于 TCHAR 数据类型,而该数据类型又取决于是否定义了符号 _UNICODE。 如果未定义 _UNICODE,则将 TCHAR 定义为 char,并且 CString 包含一个多字节字符串;如果定义了 _UNICODE,则将 TCHAR 定义为 wchar_t,并且 CString 包含一个宽字符串。

CStringA 包含 char 类型并支持单字节或多字节字符串。 CStringW 是宽字符版本。 CStringA 和 CStringW 不使用 _UNICODE 来确定它们应该如何编译。

// convert_from_cstring.cpp
// compile with: /clr /Zc:twoPhase- /link comsuppw.lib#include <iostream>
#include <stdlib.h>
#include <string>#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"using namespace std;
using namespace System;int main()
{// Set up a multibyte CStringA string.CStringA origa("Hello, World!");cout << origa << " (CStringA)" << endl;// Set up a wide character CStringW string.CStringW origw("Hello, World!");wcout << (LPCTSTR)origw << L" (CStringW)" << endl;// Convert to a char* string from CStringA string// and display the result.const size_t newsizea = origa.GetLength() + 1;char* nstringa = new char[newsizea];strcpy_s(nstringa, newsizea, origa);cout << nstringa << " (char *)" << endl;delete []nstringa;// Convert to a char* string from a wide character// CStringW string. To be safe, we allocate two bytes for each// character in the original string, including the terminating// null.const size_t newsizew = (origw.GetLength() + 1) * 2;char* nstringw = new char[newsizew];size_t convertedCharsw = 0;wcstombs_s(&convertedCharsw, nstringw, newsizew, origw, _TRUNCATE);cout << nstringw << " (char *)" << endl;delete []nstringw;// Convert to a wchar_t* from CStringAsize_t convertedCharsa = 0;wchar_t* wcstring = new wchar_t[newsizea];mbstowcs_s(&convertedCharsa, wcstring, newsizea, origa, _TRUNCATE);wcout << wcstring << L" (wchar_t *)" << endl;delete []wcstring;// Convert to a wide character wchar_t* string from// a wide character CStringW string.wchar_t* n2stringw = new wchar_t[newsizew];wcscpy_s(n2stringw, newsizew, origw);wcout << n2stringw << L" (wchar_t *)" << endl;delete []n2stringw;// Convert to a wide character _bstr_t string from// a multibyte CStringA string._bstr_t bstrt(origa);bstrt += L" (_bstr_t)";wcout << bstrt << endl;// Convert to a wide character _bstr_t string from// a wide character CStringW string.bstr_t bstrtw(origw);bstrtw += " (_bstr_t)";wcout << bstrtw << endl;// Convert to a wide character CComBSTR string from// a multibyte character CStringA string.CComBSTR ccombstr(origa);if (ccombstr.Append(L" (CComBSTR)") == S_OK){// Convert the wide character string to multibyte// for printing.CW2A printstr(ccombstr);cout << printstr << endl;}// Convert to a wide character CComBSTR string from// a wide character CStringW string.CComBSTR ccombstrw(origw);// Append the type of string to it, and display the result.if (ccombstrw.Append(L" (CComBSTR)") == S_OK){CW2A printstrw(ccombstrw);wcout << printstrw << endl;}// Convert a multibyte character CStringA to a// multibyte version of a basic_string string.string basicstring(origa);basicstring += " (basic_string)";cout << basicstring << endl;// Convert a wide character CStringW to a// wide character version of a basic_string// string.wstring basicstringw(origw);basicstringw += L" (basic_string)";wcout << basicstringw << endl;// Convert a multibyte character CStringA to a// System::String.String^ systemstring = gcnew String(origa);systemstring += " (System::String)";Console::WriteLine("{0}", systemstring);delete systemstring;// Convert a wide character CStringW to a// System::String.String^ systemstringw = gcnew String(origw);systemstringw += " (System::String)";Console::WriteLine("{0}", systemstringw);delete systemstringw;
}

3.6 从 basic_string 转换

// convert_from_basic_string.cpp
// compile with: /clr /Zc:twoPhase- /link comsuppw.lib#include <iostream>
#include <stdlib.h>
#include <string>#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"using namespace std;
using namespace System;int main()
{// Set up a basic_string string.string orig("Hello, World!");cout << orig << " (basic_string)" << endl;// Convert a wide character basic_string string to a multibyte char*// string. To be safe, we allocate two bytes for each character// in the original string, including the terminating null.const size_t newsize = (orig.size() + 1) * 2;char* nstring = new char[newsize];strcpy_s(nstring, newsize, orig.c_str());cout << nstring << " (char *)" << endl;delete []nstring;// Convert a basic_string string to a wide character// wchar_t* string. You must first convert to a char*// for this to work.const size_t newsizew = orig.size() + 1;size_t convertedChars = 0;wchar_t* wcstring = new wchar_t[newsizew];mbstowcs_s(&convertedChars, wcstring, newsizew, orig.c_str(), _TRUNCATE);wcout << wcstring << L" (wchar_t *)" << endl;delete []wcstring;// Convert a basic_string string to a wide character// _bstr_t string._bstr_t bstrt(orig.c_str());bstrt += L" (_bstr_t)";wcout << bstrt << endl;// Convert a basic_string string to a wide character// CComBSTR string.CComBSTR ccombstr(orig.c_str());if (ccombstr.Append(L" (CComBSTR)") == S_OK){// Make a multibyte version of the CComBSTR string// and display the result.CW2A printstr(ccombstr);cout << printstr << endl;}// Convert a basic_string string into a multibyte// CStringA string.CStringA cstring(orig.c_str());cstring += " (CStringA)";cout << cstring << endl;// Convert a basic_string string into a wide// character CStringW string.CStringW cstringw(orig.c_str());cstringw += L" (CStringW)";wcout << (LPCTSTR)cstringw << endl;// Convert a basic_string string to a System::StringString^ systemstring = gcnew String(orig.c_str());systemstring += " (System::String)";Console::WriteLine("{0}", systemstring);delete systemstring;
}

3.7 从 System::String 转换

// convert_from_system_string.cpp
// compile with: /clr /Zc:twoPhase- /link comsuppw.lib#include <iostream>
#include <stdlib.h>
#include <string>#include "atlbase.h"
#include "atlstr.h"
#include "comutil.h"
#include "vcclr.h"using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;int main()
{// Set up a System::String and display the result.String^ orig = gcnew String("Hello, World!");Console::WriteLine("{0} (System::String)", orig);// Obtain a pointer to the System::String in order to// first lock memory into place, so that the// Garbage Collector (GC) cannot move that object// while we call native functions.pin_ptr<const wchar_t> wch = PtrToStringChars(orig);// Make a copy of the System::String as a multibyte// char* string. Allocate two bytes in the multibyte// output string for every wide character in the input// string, including space for a terminating null.size_t origsize = wcslen(wch) + 1;const size_t newsize = origsize * 2;size_t convertedChars = 0;char* nstring = new char[newsize];wcstombs_s(&convertedChars, nstring, newsize, wch, _TRUNCATE);cout << nstring << " (char *)" << endl;delete []nstring;// Convert a wide character System::String to a// wide character wchar_t* string.const size_t newsizew = origsize;wchar_t* wcstring = new wchar_t[newsizew];wcscpy_s(wcstring, newsizew, wch);wcout << wcstring << L" (wchar_t *)" << endl;delete []wcstring;// Convert a wide character System::String to a// wide character _bstr_t string._bstr_t bstrt(wch);bstrt += " (_bstr_t)";cout << bstrt << endl;// Convert a wide character System::String// to a wide character CComBSTR string.CComBSTR ccombstr(wch);if (ccombstr.Append(L" (CComBSTR)") == S_OK){// Make a multibyte copy of the CComBSTR string// and display the result.CW2A printstr(ccombstr);cout << printstr << endl;}// Convert a wide character System::String to// a multibyte CStringA string.CStringA cstring(wch);cstring += " (CStringA)";cout << cstring << endl;// Convert a wide character System::String to// a wide character CStringW string.CStringW cstringw(wch);cstringw += " (CStringW)";wcout << (LPCTSTR)cstringw << endl;// Convert a wide character System::String to// a wide character basic_string.wstring basicstring(wch);basicstring += L" (basic_string)";wcout << basicstring << endl;delete orig;
}

3.8 WideCharToMultiByte

传统的 C 和 Windows 应用在处理窄字符串和宽字符串时使用代码页而不是 Unicode 编码。

.NET 字符串是 UTF-16,但 ATL 的 CStringA 是一个窄字符串,由 WideCharToMultiByte Win32 函数执行从宽到窄的转换。 将 C 样式的 CHAR*(C 样式的 CHAR* 是 .NET byte*)转换为字符串时,会调用相反的 Win32 函数 MultiByteToWideChar。

这两个函数都依赖于代码页的 Windows 概念;不是区域性的 .NET 概念。 若要更改系统代码页,请通过以下方式使用区域设置:使用“控制面板”> 在搜索框中输入 Region>“区域(更改日期、时间或数字格式)”>“管理”>“更改系统区域设置”。

ISDSC_STATUS DiscpUnicodeToAnsiSize(IN __in PWCHAR UnicodeString,OUT ULONG *AnsiSizeInBytes)
/*++
Routine Description:This routine will return the length needed to represent the unicodestring as ANSI
Arguments:UnicodeString is the unicode string whose ansi length is returned*AnsiSizeInBytes is number of bytes needed to represent unicodestring as ANSI
Return Value:ERROR_SUCCESS or error code
--*/
{_try{*AnsiSizeInBytes = WideCharToMultiByte(CP_ACP,0,UnicodeString,-1,NULL,0, NULL, NULL);} _except(EXCEPTION_EXECUTE_HANDLER) {return(ERROR_NOACCESS);}return((*AnsiSizeInBytes == 0) ? GetLastError() : ERROR_SUCCESS);
}
catch (std::exception e)
{// Save in-memory logging buffer to a log file on error.::std::wstring wideWhat;if (e.what() != nullptr){int convertResult = MultiByteToWideChar(CP_UTF8, 0, e.what(), (int)strlen(e.what()), NULL, 0);if (convertResult <= 0){wideWhat = L"Exception occurred: Failure to convert its message text using MultiByteToWideChar: convertResult=";wideWhat += convertResult.ToString()->Data();wideWhat += L"  GetLastError()=";wideWhat += GetLastError().ToString()->Data();}else{wideWhat.resize(convertResult + 10);convertResult = MultiByteToWideChar(CP_UTF8, 0, e.what(), (int)strlen(e.what()), &wideWhat[0], (int)wideWhat.size());if (convertResult <= 0){wideWhat = L"Exception occurred: Failure to convert its message text using MultiByteToWideChar: convertResult=";wideWhat += convertResult.ToString()->Data();wideWhat += L"  GetLastError()=";wideWhat += GetLastError().ToString()->Data();}else{wideWhat.insert(0, L"Exception occurred: ");}}}else{wideWhat = L"Exception occurred: Unknown.";}Platform::String^ errorMessage = ref new Platform::String(wideWhat.c_str());// The session added the channel at level Warning. Log the message at// level Error which is above (more critical than) Warning, which// means it will actually get logged._channel->LogMessage(errorMessage, LoggingLevel::Error);SaveLogInMemoryToFileAsync().then([=](StorageFile^ logFile) {_logFileGeneratedCount++;StatusChanged(this, ref new LoggingScenarioEventArgs(LoggingScenarioEventType::LogFileGenerated, logFile->Path->Data()));}).wait();
}

4、boost库

boost 字符类型转换一般都是用lexical_cast,还有一种转换方式是使用convert。其实convert只是封装了一个框架,不负责具体类型转换业务,而lexical_cast就可以为convert使用。

#include <iostream>
#include <string>#include <boost/convert.hpp>
#include <boost/convert/lexical_cast.hpp>void main()
{boost::cnv::lexical_cast cnv;boost::optional<int> v = boost::convert<int>("1234", cnv);//转换失败会抛出异常,这里没处理int v1 = boost::convert<int>("1234", cnv).value_or(-1);
}
#include <boost/convert/lexical_cast.hpp>
boost::cnv::lexical_cast cnv1;#include <boost/convert/strtol.hpp>
boost::cnv::strtol cnv2;#include <boost/convert/spirit.hpp>
boost::cnv::spirit cnv3;#include <boost/convert/stream.hpp>
boost::cnv::cstream ccnv4;
boost::cnv::wstream wcnv4;#include <boost/convert/printf.hpp>
boost::cnv::printf cnv5;
int i1 = convert<int>("e32c", ccnv(std::hex)).value_or(-1); //失败返回-1
int i2 = convert<int>(" 1234", cnv1(boost::cnv::parameter::base=boost::cnv::base::dec)).value_or(-1); //类型赋值
std::string i3 = convert<std::string>(1234, ccnv(std::hex)).value_or("bad"); int          i2 = convert<int>("   123", cnv(std::skipws)).value(); // Success
string       s1 = lexical_cast<string>(12.34567);
string       s2 = convert<string>(12.34567, cnv(std::fixed)(std::setprecision(3))).value();
string       s3 = convert<string>(12.34567, cnv(std::scientific)(std::setprecision(3))).value();
string expected = local::is_msc ? "1.235e+001" : "1.235e+01";

5、fmt库

https://github.com/fmtlib/fmt

{fmt}是一个开源格式化库,为 C stdio 和 C++ iostreams 提供了一种快速且安全的替代方案。实现了 C++20 的 std::format 标准。fmt 基于 CMakeLists.txt 开发,引入到项目中非常简单。

  • 带有用于本地化的位置参数的简单格式 API
  • C++20 std::format的实现
  • 格式化字符串语法类似于 Python 的 格式
  • 快速的 IEEE 754 浮点格式化程序,具有正确的舍入、缩短和往返保证
  • 安全的printf 实现,包括位置参数的 POSIX 扩展
  • 可扩展性:支持用户定义的类型
  • 高性能:比 (s)printf、iostreamsto_string和的常见标准库实现更快to_chars,请参阅速度测试 和每秒将一亿个整数转换为字符串
  • 就源代码而言,代码量小,最小配置仅包含三个文件、、core.h和format.h、format-inl.h和编译代码;请参阅编译时间和代码膨胀
  • 可靠性:该库具有广泛的测试集,并且不断进行模糊测试
  • 安全性:库是完全类型安全的,可以在编译时报告格式字符串中的错误,自动内存管理防止缓冲区溢出错误
  • 易用性:小型自包含代码库,无外部依赖项,宽松的 MIT许可证
  • 具有跨平台一致输出的可移植性和对旧编译器的支持
  • 即使在高警告级别上也能清理无警告代码库,例如 -Wall -Wextra -pedantic
  • 默认情况下与区域无关
  • FMT_HEADER_ONLY使用宏启用了可选的仅标头配置

5.1 下载和编译

git clone  https://github.com/fmtlib/fmt.git
cmake .
make && make install
编译选项要使用 -std=c++11  -lfmt 以及指定链接库和头文件位置

我放到的是项目的 dependencies 目录,然后在 CMake 中加上这两句:

add_subdirectory(dependencies/fmt EXCLUDE_FROM_ALL)
target_link_libraries(fmt_demo fmt-header-only)
cmake_minimum_required(VERSION 3.17)
set(CMAKE_CXX_STANDARD 17)
project(fmt-sample)
include(FetchContent)FetchContent_Declare(fmtURL https://github.com/fmtlib/fmt/archive/refs/tags/8.0.1.tar.gz)
FetchContent_MakeAvailable(fmt)add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} fmt)

5.2 测试代码

  • 打印到标准输出
#include <fmt/core.h>int main() {fmt::print("Hello, world!\n");
}
  • 格式化字符串
std::string s = fmt::format("The answer is {}.", 42);
// s == "The answer is 42."std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."
  • 打印计时持续时间
#include <fmt/chrono.h>int main() {using namespace std::literals::chrono_literals;fmt::print("Default format: {} {}\n", 42s, 100ms);fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}
  • 打印一个容器
#include <vector>
#include <fmt/ranges.h>int main() {std::vector<int> v = {1, 2, 3};fmt::print("{}\n", v);
}
  • 在编译时检查格式字符串
std::string s = fmt::format("{:d}", "I am not a number");
  • 从单个线程写入文件
#include <fmt/os.h>int main() {auto out = fmt::output_file("guide.txt");out.print("Don't {}", "Panic");
}
  • 使用颜色和文本样式打印
#include <fmt/color.h>int main() {fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,"Hello, {}!\n", "world");fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |fmt::emphasis::underline, "Hello, {}!\n", "мир");fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,"Hello, {}!\n", "世界");
}

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!


C++20 实现字符串类型的转换操作相关推荐

  1. mysql 将字符串转换数字类型的_MySQL 字符串类型用数字可以查出来 MySQL字符串类型会转换成数字 MySQL隐式类型转换...

    一.发现问题 1.在一次MySQL查询中,某字段为 varchar 字符串类型,传入参数值为 int 数字类型,发现查询的结果和预期的不一致. 如: 某两列 name='11' , name = '1 ...

  2. 基本数据类型和字符串类型的转换

    #include <stdio.h>void main() {char str1[20]; //字符数组,即字符串char str2[20];char str3[20];int a=209 ...

  3. C++中数字和字符串类型的转换

    // 编译环境: VS2013,C++11#include "stdafx.h" #include <iostream> #include <string> ...

  4. Java字符串编码和转换操作

    简介: 在java程序的class里,字符串以utf-8编码保存.在程序处理中,需要进行字符串编码转换时,使用getByte指定编码. 在java程序中,定义的字符串,在class文件中,字符串是以u ...

  5. 在java中实现日期类型和字符串类型的转换大全(Date String Timestamp Datetime)

    用Timestamp来记录日期时间还是很方便的,但有时候显示的时候是不需要小数位后面的毫秒的,这样就需要在转换为String时重新定义格式. Date.String.Timestamp之间的转换!   ...

  6. python 字符串 类型互相转换 str bytes 字符串连接

    直接看例子: n = 888 print bytes(n)+str1 print str(n)+str1 print type(n) n = bytes(n) print type(n) n = st ...

  7. Qt学习笔记之 字符串类型小结

    1. Qt常用字符串类型 1.1 QString QString是Unicode编码的字符串,存储一系列16位的QChar,每一个QChar对应一个Unicode 4.0编码的字符,详见<Qt学 ...

  8. php 字符串编码方式转换,PHP 字符串编码的转换

    GBK 和 UTF-8 编码的转换是一个非常恶心的事情,比如像 PHP 中的 json_encode 本身根本不支持 GBK 形式的编码.有两个库函数能够支持编码的转换,通常能够想到的就是 iconv ...

  9. 详解 Spark RDD 的转换操作与行动操作

    前言 本期继续讲解 Spark 核心 RDD 编程部分,内容比较干货也比较长,建议大家先收藏. 学习目标 RDD 的创建 RDD 的转换操作 RDD 的行动操作 惰性求值 1. RDD 的创建 Spa ...

  10. python字符串的大小写转换

    字符串的大小写转换操作: upper():把字符串中所有字符都转换成大写字母,转换的结果是新的字符串对象(即id不同) lower():把字符串中所有字符都转换成小写字母,转换的结果是新的字符串对象( ...

最新文章

  1. PyTorch框架:(6)图像识别实战常用模块解读
  2. 使用JQuery Validate插件的报Cannot read property 'settings' of undefined错误的解决方法
  3. 踩到一个Emit的坑,留个纪念
  4. springmvc-配置文件
  5. SQL 语句优化--IN语句优化案例
  6. 一键锁屏_ios快捷指令一键登录校园网(桂航为例,哆点认证)
  7. kaldi 源码分析(七) - HCLG 分析
  8. ArcMap 导入 wrl_飞时达总图软件GPCADZ三角曲面模型导入三维配管PDMS软件
  9. bindZip下载地址
  10. ybc_art打印艺术字
  11. 用AI画一只漂亮的羽毛
  12. kafka集群如何内外网均可访问
  13. python turtle 绘图小猪佩奇_python海龟作图完成小猪佩奇
  14. 修改滚动条样式的方法
  15. 这58张图片,能让你笑出八块腹肌!
  16. 防范网络钓鱼仍然很重要!
  17. python3 pdf书_用python3在PDF上书写文本
  18. Python - 装机系列66 pandas读取excel的问题
  19. 20155317王新玮《网络对抗》Exp2 后门原理与实践
  20. Unity绘制电线(三维空间两点生成曲线)

热门文章

  1. php判断是否submit,submit什么意思 php提交表单时判断 if$_POST[submit]与 ifisset$_POST[submit] 的区别...
  2. JSP智能小区物业管理系统
  3. 阿古斯机器人_7.3.2暗牧神器燃烧王座语音
  4. Mac安装brew及adb环境
  5. Echarts 修改地图的标示
  6. c++可视化性能测试
  7. 下午茶,几个笑话提提神
  8. 统计push点击次数的shell脚本版本2
  9. c语言编程计算税后收入,C语言编写一个计算个人所得税的程序,要求输入收入金额,能够输...
  10. 这是我见过最秀的代码 。。。