다음과 같은 줄로 std :: string을 생성하려면
std::string my_string("a\0b");
결과 문자열 (a, null, b)에 세 문자를 포함하고 싶은 경우 하나만 얻습니다. 적절한 구문은 무엇입니까?
답변:
우리는 리터럴을 만들 수있었습니다 std::string
#include <iostream>
#include <string>
int main()
{
using namespace std::string_literals;
std::string s = "pl-\0-op"s; // <- Notice the "s" at the end
// This is a std::string literal not
// a C-String literal.
std::cout << s << "\n";
}
문제는 입력이 C- 문자열이라고 가정 하는 std::string
생성자입니다 const char*
. C- 문자열은 \0
종료되므로 \0
문자에 도달하면 구문 분석이 중지됩니다 .
이를 보완하려면 C-String이 아닌 char 배열에서 문자열을 작성하는 생성자를 사용해야합니다. 여기에는 배열에 대한 포인터와 길이의 두 매개 변수가 필요합니다.
std::string x("pq\0rs"); // Two characters because input assumed to be C-String
std::string x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.
참고 : C ++ std::string
는 종료 되지 않습니다 \0
(다른 게시물에서 제 안됨). 그러나 메서드를 사용하여 C-String을 포함하는 내부 버퍼에 대한 포인터를 추출 할 수 있습니다 c_str()
.
사용에 대한 Doug T의 답변을 아래 에서 확인하십시오 vector<char>
.
또한 RiaD 에서 C ++ 14 솔루션을 확인하십시오 .
c 스타일 문자열 (문자 배열)과 같은 조작을 수행하는 경우 다음을 사용하는 것이 좋습니다.
std::vector<char>
c- 문자열을 처리하는 것과 같은 방식으로 배열처럼 처리 할 수있는 더 많은 자유가 있습니다. copy ()를 사용하여 문자열로 복사 할 수 있습니다.
std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
c- 문자열을 사용할 수있는 동일한 위치에서 사용할 수 있습니다.
printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';
그러나 당연히 c- 문자열과 동일한 문제가 발생합니다. 널 터미널을 잊거나 할당 된 공간을 지나서 쓸 수 있습니다.
byte *bytes = new byte[dataSize]; std::memcpy(bytes, image.data, dataSize * sizeof(byte)); std::string test(reinterpret_cast<char *>(bytes)); std::cout << "Encoded String length " << test.length() << std::endl;
나는 아무 생각이 없다 왜 당신이 그런 일을 할 수 있지만,이 시도 할 것을 :
std::string my_string("a\0b", 3);
vector<unsigned char>
또는 unsigned char *
발명되었습니다.
std::string
데이터가 일반 텍스트로 간주되어야 함을 나타 내기 위해 사용 하지만 일부 해싱 작업을 수행하고 있으며 모든 것이 여전히 null 문자와 함께 작동하는지 확인하고 싶습니다. 널 문자가 포함 된 문자열 리터럴의 유효한 사용처럼 보입니다.
\0
UTF-8 문자열 의 바이트는 NUL 만 될 수 있습니다. 멀티 바이트로 인코딩 된 문자에는 \0
해당 문제에 대한 다른 ASCII 문자도 포함되지 않습니다 .
사용자 정의 리터럴이 C ++에 추가하는 새로운 기능은 무엇입니까? 우아한 대답을 제시합니다. 정의
std::string operator "" _s(const char* str, size_t n)
{
return std::string(str, n);
}
그런 다음 다음과 같이 문자열을 만들 수 있습니다.
std::string my_string("a\0b"_s);
또는 심지어 :
auto my_string = "a\0b"_s;
"오래된 스타일"방식이 있습니다.
#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
그런 다음 정의 할 수 있습니다.
std::string my_string(S("a\0b"));
이것에주의해야합니다. 'b'를 숫자로 바꾸면 대부분의 방법을 사용하여 자동으로 잘못된 문자열을 만듭니다. 참조 : C ++ 문자열 리터럴 이스케이프 문자 규칙 .
예를 들어, 프로그램 중간에이 무고 해 보이는 스 니펫을 떨어 뜨 렸습니다.
// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
std::cerr << c;
// 'Q' is way cooler than '\0' or '0'
c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
std::cerr << c;
}
std::cerr << "\n";
이 프로그램이 나에게 출력하는 내용은 다음과 같습니다.
Entering loop.
Entering loop.
vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
그것은 두 번의 첫 번째 인쇄 문이었습니다. 몇 개의 인쇄되지 않는 문자와 줄 바꿈, 내부 메모리의 내용이 뒤따 랐습니다. 이는 방금 덮어 썼습니다 (덮어 썼다는 것을 보여주는 인쇄). 무엇보다도,이를 철저하고 장황한 gcc 경고로 컴파일해도 문제가 있음을 알 수 없었으며 valgrind를 통해 프로그램을 실행해도 부적절한 메모리 액세스 패턴에 대해 불평하지 않았습니다. 즉, 최신 도구로는 완전히 감지 할 수 없습니다.
훨씬 더 간단한으로도 동일한 문제를 얻을 수 std::string("0", 100);
있지만 위의 예는 조금 더 까다로워서 무엇이 잘못되었는지 확인하기가 더 어렵습니다.
다행히 C ++ 11은 이니셜 라이저 목록 구문을 사용하여 문제에 대한 좋은 해결책을 제공합니다. 이렇게하면 문자 수를 지정하지 않아도되고 (위에서 보여 드린대로 잘못 수행 할 수 있음) 이스케이프 된 숫자 조합을 피할 수 있습니다. std::string str({'a', '\0', 'b'})
배열 char
및 크기 를 사용하는 버전과 달리 모든 문자열 콘텐츠에 안전합니다 .
C ++ 14에서는 이제 리터럴을 사용할 수 있습니다.
using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
auto s{"a\0b"s};
anonym의 대답은 훌륭하지만 C ++ 98에는 비 매크로 솔루션도 있습니다.
template <size_t N>
std::string RawString(const char (&ch)[N])
{
return std::string(ch, N-1); // Again, exclude trailing `null`
}
이 함수를 사용하면 다음과 RawString(/* literal */)
같은 문자열이 생성됩니다 S(/* literal */)
.
std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;
또한 매크로에 문제가 있습니다. 표현식은 실제로 std::string
작성된 것이 아니므 로 간단한 할당 초기화에 사용할 수 없습니다.
std::string s = S("a\0b"); // ERROR!
... 따라서 다음을 사용하는 것이 좋습니다.
#define std::string(s, sizeof s - 1)
프로젝트에서 하나 또는 다른 솔루션 만 사용하고 적절하다고 생각하는 이름으로 불러야합니다.
나는이 질문이 오랫동안 제기되었다는 것을 알고 있습니다. 그러나 비슷한 문제가있는 사람이라면 다음 코드에 관심이있을 수 있습니다.
CComBSTR(20,"mystring1\0mystring2\0")
std :: strings의 거의 모든 구현은 null로 종료되므로이 작업을 수행해서는 안됩니다. "a \ 0b"는 자동 널 종결 자 (a, 널, b, 널)로 인해 실제로 4 자 길이입니다. 정말로 이것을하고 std :: string의 계약을 깨고 싶다면 다음과 같이 할 수 있습니다.
std::string s("aab");
s.at(1) = '\0';
그러나 그렇게한다면 모든 친구들이 당신을 비웃을 것이고 진정한 행복을 찾을 수 없을 것입니다.