No momento, estou trabalhando com sistemas embarcados e descobrindo maneiras de implementar seqüências de caracteres em um microprocessador sem sistema operacional. Até agora, o que estou fazendo é apenas usar a idéia de ter ponteiros de caracteres terminados em NULL e tratá-los como cadeias de caracteres em que o NULL significa o fim. Eu sei que isso é bastante comum, mas você pode sempre contar com esse para ser o caso?
A razão pela qual pergunto é que estava pensando em usar um sistema operacional em tempo real em algum momento e gostaria de reutilizar o máximo possível meu código atual. Então, para as várias opções disponíveis, posso esperar que as strings funcionem da mesma forma?
Deixe-me ser mais específico, porém, para o meu caso. Estou implementando um sistema que aceita e processa comandos por uma porta serial. Posso manter meu código de processamento de comando igual e, em seguida, esperar que os objetos de seqüência de caracteres criados no RTOS (que contém os comandos) sejam todos terminados em NULL? Ou seria diferente com base no sistema operacional?
Atualizar
Depois de ser aconselhado a dar uma olhada nesta pergunta , concluí que ela não responde exatamente o que estou perguntando. A pergunta em si está perguntando se o comprimento de uma string deve sempre ser passado, o que é totalmente diferente do que estou perguntando, e embora algumas das respostas tenham informações úteis, elas não são exatamente o que estou procurando. As respostas pareciam dar razões pelas quais ou por que não terminar uma sequência com um caractere nulo. A diferença com o que estou perguntando é se posso mais ou menos esperar que as strings nativas de plataformas diferentes terminem suas próprias strings com nulo, sem ter que sair e tentar todas as plataformas existentes, se isso fizer sentido.
Respostas:
As coisas chamadas "strings C" serão terminadas em nulo em qualquer plataforma. É assim que as funções padrão da biblioteca C determinam o final de uma string.
Na linguagem C, não há nada que o impeça de ter uma matriz de caracteres que não termina em um nulo. No entanto, você terá que usar outro método para evitar o final de uma string.
fonte
char
matrizes terminadas em nulo ,char
matrizes com o comprimento codificado no primeiro byte (comumente conhecido como "strings Pascal"),wchar_t
versões baseadas em ambos os acima echar
matrizes que combinam os dois métodos: comprimento codificado no primeiro byte e um caractere nulo que termina a cadeia.A determinação do caractere final depende do compilador para literais e da implementação da biblioteca padrão para cadeias em geral. Não é determinado pelo sistema operacional.
A convenção de
NUL
rescisão remonta ao C pré-padrão e, em mais de 30 anos, não posso dizer que me deparei com um ambiente que faz qualquer outra coisa. Esse comportamento foi codificado em C89 e continua a fazer parte do padrão da linguagem C (o link está para um rascunho de C99):NUL
cadeias terminadas exigindo que umNUL
seja anexado a literais de cadeias.Não há razão para que alguém não possa escrever funções que lidam com seqüências terminadas por algum outro caractere, mas também não há razão para reverter o padrão estabelecido na maioria dos casos, a menos que seu objetivo seja adequar os programadores. :-)
fonte
printf("string: \"%s\"\n", "my cool string")
. A única maneira de contornar quatro parâmetros nesse caso (além de algum tipo de byte de terminação) seria definir uma string como algostd::string
em C ++, que tem seus próprios problemas e limitações.NUL
terminam, não importa o que: "Na fase de tradução 7, um byte ou código do valor zero é anexado a cada sequência de caracteres multibyte que resulta de uma string literal ou literals ". As funções da biblioteca que usam a definição do 7.1.1 são interrompidas no momento emNUL
que encontram e não sabem nem se importam com a existência de caracteres adicionais além dela.Não há tipo de dados de string na linguagem C, mas existem literais de string .
Se você colocar uma string literal em seu programa, ela normalmente será encerrada em NUL (mas veja o caso especial, discutido nos comentários abaixo.) Ou seja, se você colocar
"foobar"
em um local ondeconst char *
se espera um valor, o compilador emitiráfoobar⊘
para o segmento const / code / seção do seu programa e o valor da expressão será um ponteiro para o endereço em que ele armazenou of
caractere. (Nota: estou usando⊘
para significar o byte NUL.)O único outro sentido em que a linguagem C possui seqüências é que ela possui algumas rotinas de biblioteca padrão que operam em seqüências de caracteres terminadas em NUL. Essas rotinas de biblioteca não existirão em um ambiente bare metal, a menos que você as porte.
Eles são apenas códigos - não diferentes do código que você escreve. Se você não quebrá-los quando os portar, eles farão o que sempre fazem (por exemplo, parem em um NUL).
fonte
char foo[4] = "abcd";
é uma maneira válida de criar uma matriz de quatro caracteres com terminação não nula.char const *
expressão é esperada. Eu esqueci que os inicializadores C às vezes podem obedecer a regras diferentes.char[4]
. Isso não é uma string, mas foi inicializado a partir de umastatic
- chave ao exemplo de Ruakh, o compilador poderá emitir um "abcd" não NUL terminado para um segmento de dados inicializado, para que a variável seja inicializada pelo carregador do programa. Portanto, Ruakh estava certo: há pelo menos um caso em que a aparência de uma string literal em um programa não requer que o compilador emita uma string terminada em NUL. (ps, na verdade, compilei o exemplo com o gcc 5.4.0 e o compilador não emitiu o NUL.)Como outros já mencionaram, o encerramento nulo de seqüências de caracteres é uma convenção da C Standard Library. Você pode manipular as strings da maneira que desejar, se não for usar a biblioteca padrão.
Isso vale para qualquer sistema operacional com um compilador 'C' e, também, você pode escrever programas 'C' que não são executados em um sistema operacional verdadeiro, como você mencionou na sua pergunta. Um exemplo seria o controlador de uma impressora a jato de tinta que eu projetei uma vez. Em sistemas incorporados, a sobrecarga de memória de um sistema operacional pode não ser necessária.
Em situações de falta de memória, eu examinaria as características do meu compilador em relação ao conjunto de instruções do processador, por exemplo. Em um aplicativo em que as strings são processadas muito, pode ser desejável usar descritores como comprimento da string. Estou pensando em um caso em que a CPU é particularmente eficiente em trabalhar com desvios curtos e / ou desvios relativos com registros de endereço.
Então, o que é mais importante no seu aplicativo: tamanho e eficiência do código ou compatibilidade com um sistema operacional ou biblioteca? Outra consideração pode ser a manutenção. Quanto mais você se afastar da convenção, mais difícil será para alguém manter.
fonte
Outros abordaram a questão de que, em C, as strings são basicamente o que você faz delas. Mas parece haver alguma confusão em sua pergunta no próprio terminador e, de uma perspectiva, pode ser com isso que alguém em sua posição está preocupado.
As strings C são terminadas em nulo. Ou seja, eles são finalizados pelo caractere nulo
NUL
,. Eles não são finalizados pelo ponteiro nuloNULL
, que é um tipo de valor completamente diferente, com uma finalidade completamente diferente.NUL
é garantido que o valor inteiro seja zero. Dentro da string, ele também terá o tamanho do tipo de caractere subjacente, que geralmente será 1.NULL
não é garantido que tenha um tipo inteiro.NULL
destina-se ao uso em um contexto de ponteiro e, geralmente, espera-se que ele tenha um tipo de ponteiro, que não deve ser convertido em um caractere ou número inteiro se o seu compilador for bom. Embora a definição deNULL
envolva o glifo0
, não é garantido que ele realmente tenha esse valor [1], e a menos que o seu compilador implemente a constante como um caractere#define
(muitos não, porque muitos não devem , porqueNULL
realmente não devem ser significativos em um elemento não contexto do ponteiro), portanto, não é garantido que o código expandido envolva realmente um valor zero (mesmo que de forma confusa envolva um glifo zero).Se
NULL
digitado, também não será provável que tenha um tamanho de 1 (ou outro tamanho de caractere). Isso pode causar problemas adicionais, embora as constantes reais de caracteres também não tenham tamanho de caracteres.Agora, a maioria das pessoas verá isso e pensará: "ponteiro nulo como qualquer coisa que não seja zero-bits? Que bobagem" - mas suposições como essa só são seguras em plataformas comuns como o x86. Como você mencionou explicitamente o interesse em segmentar outras plataformas, é necessário levar esse problema em consideração, pois separou explicitamente seu código de suposições sobre a natureza do relacionamento entre ponteiros e números inteiros.
Portanto, enquanto as strings C são terminadas em nulo, elas não são terminadas por
NULL
, mas porNUL
(geralmente escritas'\0'
). O código que usa explicitamenteNULL
como um terminador de strings funcionará em plataformas com uma estrutura de endereços direta e até compilará com muitos compiladores, mas não está absolutamente correto.[1] o valor real do ponteiro nulo é inserido pelo compilador quando ele lê um
0
token em um contexto em que seria convertido em um tipo de ponteiro. Esta não é uma conversão do valor inteiro 0 e não é garantida a retenção se algo diferente do0
próprio token for usado, como um valor dinâmico de uma variável; a conversão também não é reversível e um ponteiro nulo não precisa gerar o valor 0 quando convertido em um número inteiro.fonte
NUL
é garantido que o valor inteiro seja zero." -> C não defineNUL
. Em vez C define que as cordas têm uma final chracter nulo , um byte com todos os bits em 0.Eu tenho usado string em C, significa caracteres com terminação nula é chamado Strings.
Não haverá problemas quando você usar em baremetal ou em qualquer sistema operacional como Windows, Linux, RTOS: (FreeRTO, OSE).
No mundo incorporado, a terminação nula realmente ajuda mais a simbolizar o caractere como string.
Eu tenho usado seqüências de caracteres em C assim em muitos sistemas críticos de segurança.
Você pode estar se perguntando, o que é realmente uma string em C?
Seqüências de caracteres no estilo C, que são matrizes, também existem literais, como "this". Na realidade, esses dois tipos de cadeias de caracteres são apenas conjuntos de caracteres sentados um ao lado do outro na memória.
Por exemplo, você pode declarar e definir uma matriz de caracteres e inicializá-la com uma constante de sequência:
Resposta direta: você realmente não precisa se preocupar com o uso de caracteres com terminação nula, este trabalho independente de qualquer plataforma.
fonte
NUL
é automaticamente anexado.Como outros já disseram, a terminação nula é praticamente universal para o padrão C. Mas (como outros também apontaram) não 100%. Para outro exemplo, o sistema operacional VMS normalmente usava o que chamava de "descritores de string" http://h41379.www4.hpe.com/commercial/c/docs/5492p012.html acessado em C por #include <descrip.h >
As coisas no nível do aplicativo podem usar terminação nula ou não, no entanto, o desenvolvedor considera adequado. Mas as coisas de baixo nível do VMS exigem absolutamente descritores, que não usam terminação nula (veja o link acima para detalhes). Isso ocorre principalmente para que todos os idiomas (C, assembly etc.) que usam diretamente os componentes internos do VMS possam ter uma interface comum.
Portanto, se você está prevendo qualquer tipo de situação semelhante, pode ser um pouco mais cuidadoso do que o "encerramento nulo universal" pode sugerir que é necessário. Seria mais cuidadoso se estivesse fazendo o que você está fazendo, mas para minhas coisas no nível do aplicativo é seguro assumir o encerramento nulo. Eu apenas não sugeriria o mesmo nível de segurança para você. É possível que seu código precise interagir com o código de idioma assembly e / ou outro código de idioma em algum momento futuro, que nem sempre está em conformidade com o padrão C de seqüências terminadas em nulo.
fonte
Na minha experiência em sistemas embarcados, críticos para segurança e em tempo real, não é incomum usar as convenções de string C e PASCAL, ou seja, fornecer o comprimento das strings como o primeiro caractere (que limita o comprimento a 255) e finalizar o string com pelo menos um 0x00, (
NUL
), que reduz o tamanho utilizável para 254.Uma razão para isso é saber quantos dados você espera após o primeiro byte ter sido recebido e outra é que, nesses sistemas, os tamanhos dinâmicos de buffer são evitados sempre que possível - alocar um tamanho fixo de 256 buffers é mais rápido e seguro (não precisa verificar se
malloc
falhou). Outra é que os outros sistemas com os quais você está se comunicando podem não estar escritos em ANSI-C.Em qualquer trabalho incorporado, é importante estabelecer e manter um IDC (Interface Control Document), que define todas as suas estruturas de comunicação, incluindo formatos de string, endianness, tamanhos inteiros etc., o mais rápido possível ( ideal antes de iniciar ), e deve ser o seu livro sagrado, e todas as equipes, ao escrever o sistema - se alguém deseja introduzir uma nova estrutura ou formato, ele deve ser documentado primeiro e todos que possam ser impactados informados, possivelmente com a opção de vetar a mudança .
fonte