Estou aprendendo C e tentando entender como scanf funciona. Não consigo entender alguns termos: o termo "input item", "initial subsequence", "matching sequence". Estou lendo isto https://pubs.opengroup.org/onlinepubs/9699919799/functions/scanf.html . Diz:
Um item de entrada deve ser definido como a sequência mais longa de bytes de entrada (até qualquer largura máxima de campo especificada, que pode ser medida em caracteres ou bytes dependendo do especificador de conversão), que é uma subsequência inicial de uma sequência correspondente .
Suponha que no formato i tenha %d e no stdin 4.5 . O que é subsequência inicial e o que é sequência correspondente ? E o que é item de entrada ?
Pensei que o item de entrada é o que corresponde a esse especificador, ou seja, para %d os símbolos correspondentes são números (talvez sinais de + - no início), mas então ele diz:
Exceto no caso de um especificador de conversão %, o item de entrada (ou, no caso de uma especificação de conversão %n, a contagem de bytes de entrada) deve ser convertido para um tipo apropriado para o caractere de conversão. Se o item de entrada não for uma sequência correspondente , a execução da especificação de conversão falhará;
ou seja, o item de entrada pode não corresponder, o que significa que ele não consiste apenas em símbolos que correspondem ao especificador.
Então, você pode me explicar esses termos? E me dizer se é aqui que estou procurando documentação para funções C? Quais sites são os melhores lugares para ler documentação para funções C?
Um problema-chave com o qual este texto está lidando é que às vezes se uma sequência de caracteres corresponde ao padrão para uma conversão depende de caracteres ainda não lidos. Por exemplo, o texto de entrada “0x3” corresponde ao padrão para
%x
, mas o texto de entrada “0xy” não. No ponto em que lemos “0x”, “0x” por si só não corresponde ao padrão, e não sabemos se o próximo caractere formará uma sequência correspondente. Precisamos ler o próximo caractere para descobrir.Então a regra para quando
scanf
continua lendo caracteres não pode ser "Enquanto os caracteres corresponderem ao padrão de objetivo, continue lendo". Se essa fosse a regra, leríamos "0", veríamos que corresponde a uma possível entrada válida para%x
, então leríamos "x", veríamos que "0x" não é uma entrada válida para%x
, e pararíamos. Isso não funcionará, porque falha em ler "0x3", que é uma entrada válida para%x
.A regra deve ser que
scanf
continua lendo enquanto a entrada puder ser uma sequência correspondente se os caracteres vindouros completarem uma correspondência. Uma maneira de dizer isso tecnicamente é que os caracteres lidos até agora são uma subsequência inicial de uma sequência correspondente.Uma sequência correspondente para
%d
é opcionalmente um “-”, então um ou mais dígitos decimais. Considere as sequências correspondentes “123” e “-123”. Subsequências iniciais de “123” são a string vazia, “1”, “12” e “123”. Subsequências iniciais de “-123” são a string vazia, “-”, “-1”, “-12” e “-123”. Então uma subsequência inicial de uma sequência correspondente para%d
é opcionalmente um “-”, então zero ou mais dígitos decimais. Note que “-” é uma subsequência inicial, mas não uma sequência correspondente.É mais interessante considerar
%e
, onde “3.4e-5” é uma sequência correspondente, mas “3.4” ou “3.4ex” não é. Agorascanf
tem que ler dois caracteres onde não se sabe se haverá uma correspondência. Quandoscanf
leu “3.4”, essa é uma sequência correspondente, mas tem que continuar enquanto os caracteres formarem uma subsequência inicial. Em seguida, temos “3.4e”, que não é mais uma sequência correspondente, mas ainda é uma subsequência inicial. Então “3.4e-” também é uma subsequência inicial. Com “3.4e-5”, mais uma vez temos uma sequência correspondente, bem como uma subsequência inicial.scanf
deve continuar lendo. Se o próximo caractere for um espaço, “3.4e-5 ” não é uma subsequência inicial, então o espaço é rejeitado (e é “colocado de volta” no fluxo de entrada como se nunca tivesse sido lido), e “3.4e-5” é o item de entrada. Este item de entrada é uma sequência correspondente, então é convertido em umfloat
.Agora considere ler “3.4ex”. Como acima, em “3.4e”,
scanf
deve continuar lendo. Ele obtém o “x” e vê que “3.4ex” não é uma subsequência inicial. Ele rejeita o “x” e o coloca de volta no fluxo de entrada. Agora ele terminou de ler, e “3.4e” é o item de entrada. Esta não é uma sequência correspondente, então é uma falha de correspondência.scanf
não realiza uma conversão para isto, e ele retorna.Note que com “3.4ex”, se pudéssemos colocar de volta dois caracteres em vez de apenas um, poderíamos reverter para “3.4”, corresponder a isso para
%e
, e convertê-lo parafloat
. No entanto, o padrão C não requer que os fluxos de E/S suportem mais de um caractere de put-back, escanf
é especificado para trabalhar com apenas um caractere de put-back. É por isso quescanf
é especificado para ler até que uma correspondência seja impossível, então colocar de volta o caractere não correspondente, então ver se o que ele leu é uma correspondência. Se tivéssemos mais níveis de put-back,scanf
poderíamos ler até que uma correspondência seja impossível, então colocar de volta todos os caracteres necessários para reduzir a entrada para uma sequência correspondente, e então converter isso.(Observe que, conforme discutido nos comentários, algumas
scanf
implementações não estão em conformidade com esta especificação do padrão C e podem retornar vários caracteres.)Não há um único site que seja o melhor lugar, nem um pequeno conjunto de sites. O padrão C é o lugar mais confiável para ler sobre funções na biblioteca padrão C, mas entendê-las é informado pela teoria da ciência da computação e pela história do desenvolvimento da linguagem C. Com esta edição em
scanf
, a teoria sobre análise sintática, linguagens formais e máquinas de estados finitos é informativa sobre como um computador tem que ler caracteres para interpretá-los. Essas são partes do estudo de uma educação em ciência da computação, não algo que você obtém facilmente em sites com foco restrito.É um pouco confuso.
Essencialmente, scanf lê bytes para um especificador de conversão até que o próximo byte não possa ser parte do que ele deveria ler para aquele especificador de conversão. Então ele olha o que foi lido, e esse é o item de entrada para aquele especificador de conversão. (Por baixo dos panos, ele provavelmente "deslê" o próximo byte com ungetc.)
"Sequência de correspondência" significa qualquer sequência de caracteres que corresponderia à especificação de conversão. Não é restrito a sequências de caracteres que realmente aparecem na entrada. Por exemplo,
0
e0xff
são ambas sequências de correspondência para a especificação de conversão%x
.Uma "subsequência inicial de uma sequência correspondente" significa qualquer sequência de caracteres que pode ser o início de uma sequência correspondente. Por exemplo,
0
,0x
, e0xff
são todas subsequências iniciais da sequência correspondente0xff
para a especificação de conversão%x
. Elas também são subsequências iniciais de muitas outras sequências correspondentes, como0xff00
ou0xff1
.Um item de entrada é a sequência mais longa de caracteres de entrada que é uma subsequência inicial de uma sequência correspondente. Por exemplo, se a entrada for
0xgoose
e scanf estiver processando um especificador de conversão de%x
, então o item de entrada é0x
. Não é0
, embora0
seja uma sequência correspondente, e não é nada mais longo que0x
, porque nada mais longo poderia ser o início de uma sequência correspondente.sequência de correspondência
é qualquer sequência de caracteres que seja uma representação válida para o especificador de conversão usado. Não se refere à entrada real. Refere-se a toda e qualquer sequência válida (também conhecida como correspondente).
Exemplos
%d
de sequências correspondentes são123456
,987654
e muitos, muitos outros.subsequência inicial
é uma parte (ou toda) de outra sequência começando do caractere mais à esquerda, ou seja, o caractere inicial.
Por exemplo, para a sequência
1234
, as subsequências iniciais são1
,12
,123
e1234
item de entrada
é a maior subsequência inicial de uma sequência correspondente. Em outras palavras, os caracteres que serão convertidos e então armazenados na variável fornecida.
Por exemplo, para o
1234Z
especificador de sequência e conversão,%d
a maior subsequência inicial de uma sequência correspondente é1234
.Um conjunto de testes para ajudar a avaliar as respostas em comparação com o código real.
Exemplo de saída: (Observe que esta saída certamente não está em conformidade com a especificação C.)