Pergunta

Se eu quiser construir uma std :: string com uma linha como:

std::string my_string("a\0b");

Onde eu quero ter três caracteres na string resultante (a, null, b), eu só tem uma. O que é a sintaxe apropriada?

Foi útil?

Solução

Como C ++ 14

temos sido capazes de criar literal 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";
}

Antes de C ++ 14

O problema é o construtor std::string que leva um const char* assume a entrada é um C-string. Strings C são \0 encerrado e, portanto, a análise pára quando atinge o personagem \0.

Para compensar isso, você precisa usar o construtor que constrói a string a partir de uma matriz de char (não um C-String). Isso leva dois parâmetros - um ponteiro para a matriz e um comprimento:

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.

Nota: std::string C ++ é não -\0 terminado (como sugerido em outros lugares). No entanto, pode extrair um ponteiro para uma memória intermédia interna que contém um C-String com o método c_str().

Também confira abaixo sobre como usar um vector<char>.

Também vá para RIad para uma solução ++ 14 C.

Outras dicas

Se você está fazendo manipulação, como você faria com uma seqüência c-estilo (conjunto de caracteres) considerar o uso

std::vector<char>

Você tem mais liberdade para tratá-lo como um array da mesma forma que você trataria um c-string. Você pode usar copy () para copiar em uma string:

std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());

e você pode usá-lo em muitos dos mesmos lugares que você pode usar strings C

printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';

Naturalmente, no entanto, você sofre dos mesmos problemas como C-strings. Você pode esquecer o seu terminal nulo ou gravação passado o espaço alocado.

Eu não tenho idéia por que você gostaria de fazer uma coisa dessas, mas tente o seguinte:

std::string my_string("a\0b", 3);

O que novas capacidades não literais definidos pelo usuário adicionar à C ++ apresenta uma resposta elegante:? Definir

std::string operator "" _s(const char* str, size_t n) 
{ 
    return std::string(str, n); 
}

então você pode criar sua seqüência da seguinte maneira:

std::string my_string("a\0b"_s);

ou até mesmo assim:

auto my_string = "a\0b"_s;

Há uma maneira "estilo antigo":

#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string

então você pode definir

std::string my_string(S("a\0b"));

A seguir irá trabalhar ...

std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');

Você tem que ter cuidado com isso. Se você substituir 'b' com qualquer personagem numérico, você silenciosamente irá criar a seqüência de errado com a maioria dos métodos. Veja:. Regras para C ++ strings literais escapar personagem

Por exemplo, eu deixei cair esse trecho inocente no meio de um programa

// 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";

Aqui está o que esta saída do programa para mim:

Entering loop.
Entering loop.

vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ

Essa foi a minha primeira declaração de impressão duas vezes, vários caracteres não imprimíveis, seguido por uma nova linha, seguido por algo na memória interna, que eu só substituiu (e, em seguida, impresso, mostrando que tem sido substituído). Pior de tudo, até mesmo compilar esta com avisos me deu nenhuma indicação de que algo está errado, e executar o programa através valgrind não reclamar quaisquer padrões de acesso de memória impróprio. Em outras palavras, é completamente indetectável por ferramentas modernas.

Você pode obter esse mesmo problema com o std::string("0", 100); muito mais simples, mas o exemplo acima é um pouco complicado e, portanto, mais difícil de ver o que está errado.

Felizmente, C ++ 11 nos dá uma boa solução para o problema usando initializer sintaxe lista. Isso evita que você ter que especificar o número de caracteres (que, como eu mostrei acima, você pode fazer incorretamente) e evita que combinam números escaparam. std::string str({'a', '\0', 'b'}) é seguro para qualquer conteúdo corda, ao contrário das versões que levam uma série de char e um tamanho.

Em C ++ 14 agora você pode usar literais

using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3

Melhor usar std :: vector , se esta questão não é apenas para fins educacionais.

A resposta de anonym é excelente, mas há uma solução não-macro em C ++ 98, bem como:

template <size_t N>
std::string RawString(const char (&ch)[N])
{
  return std::string(ch, N-1);  // Again, exclude trailing `null`
}

Com esta função, RawString(/* literal */) irá produzir a mesma seqüência como 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;

Além disso, há um problema com a macro: a expressão não é realmente uma std::string como está escrito, e, portanto, não pode ser usado, por exemplo para simples atribuição-inicialização:

std::string s = S("a\0b"); // ERROR!

... por isso pode ser preferível usar:

#define std::string(s, sizeof s - 1)

Obviamente você deve usar apenas uma ou a outra solução no seu projeto e chamar-lhe o que você acha que é apropriado.

Eu sei que é muito tempo tem sido esta pergunta. Mas para quem está tendo um problema semelhante poderia estar interessado no código a seguir.

CComBSTR(20,"mystring1\0mystring2\0")

Quase todas as implementações de std :: strings são terminadas em null, então você provavelmente não deve fazer isso. Note-se que "a \ 0b" é, na verdade, quatro caracteres causa do terminador nulo automática (a, null, b, null). Se você realmente quer fazer isso e std :: quebra de contrato da corda, você pode fazer:

std::string s("aab");
s.at(1) = '\0';

mas se você fizer isso, todos os seus amigos vão rir de você, você nunca vai encontrar a verdadeira felicidade.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top