Por que o padrão C ++ lida com arquivos buscando a maneira como faz?

17

O C ++ usa o streamofftipo para representar um deslocamento em um fluxo (arquivo) e é definido da seguinte maneira em [stream.types]:

using streamoff = implementation-defined ;

O tipo streamoff é sinônimo de um dos tipos integrais básicos assinados de tamanho suficiente para representar o tamanho máximo possível de arquivo para o sistema operacional. 287)

287) Normalmente longo.

Isso faz sentido porque permite procurar em arquivos grandes (em vez de usar long, que podem ter apenas 32 bits de largura).

[filebuf.virtuals] define basic_filebufa função de buscar em um arquivo da seguinte maneira:

pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override;

off_typeé equivalente a streamoff, consulte [iostreams.limits.pos]. No entanto, o padrão continua a explicar os efeitos da função. Estou irritado com a última frase, que exige uma chamada para fseek:

Efeitos : Vamos widthdenotar a_codecvt.encoding(). Se is_open() == false, ou off != 0 && width <= 0, a operação de posicionamento falhará. Caso contrário, se way != basic_ios::curou off != 0, e se a última operação foi emitida, atualize a sequência de saída e escreva qualquer sequência de não mudança. Em seguida, procure a nova posição: se width > 0, ligue fseek(file, width * off, whence), caso contrário, ligue fseek(file, 0, whence).

fseekaceita um longparâmetro Se off_typee streamofffor definido como long long(conforme sugerido pelo padrão), isso poderá levar a uma conversão inativa ao longchamar fseek(file, width * off, whence)(levando a erros potencialmente difíceis de diagnosticar). Isso põe em questão toda a lógica para introduzir o streamofftipo em primeiro lugar.

Isso é intencional ou um defeito no padrão?

jceed2
fonte
8
defeito parece.
Yakk - Adam Nevraumont 13/12/19
Acho que vejo que o gcc libstdc ++ usa o fseeko64 .
KamilCuk
11
De improviso, não parece seekoffnecessariamente usar fseek sob o capô. Em vez disso, o comportamento (presumivelmente familiar?) De fseeké usado para explicar o que seekoffestá fazendo.
jjramsey
@jjramsey Esta foi a minha impressão também. No entanto, o modo como é formulado parece sugerir mais um requisito do que uma explicação.
jceed2
11
@jjramsey Concordo que a parte "Efeitos" pode ser razoavelmente interpretada para significar que na verdade não precisa ser chamada fseekdesde que faça algo com o mesmo efeito. Mas fseekcom um deslocamento menor LONG_MINou maior que LONG_MAXnão tem efeito, a explicação é, na melhor das hipóteses, incompleta, pelo menos para implementações onde streamoffé maior que long.
Keith Thompson

Respostas:

6

Eu acho que a conclusão que você está tirando disso, de que existe uma incompatibilidade entre os fluxos C ++ e fseekque levará a erros de tempo de execução, está incorreta. A situação parece ser:

  1. Em sistemas onde longé de 64 bits, streamoffé definido como longe a seekofffunção chama fseek.

  2. Em sistemas com long32 bits, mas o sistema operacional suporta compensações de arquivos de 64 bits, streamoffé definido como long longe seekoffinvoca uma função chamada fseekoou fseeko64que aceita um deslocamento de 64 bits.

Aqui está um trecho da definição de seekoffno meu sistema Linux:

#ifdef _GLIBCXX_USE_LFS
    if (!fseeko64(_M_file, __off, __whence))
      __ret = std::streampos(ftello64(_M_file));
#else
    if (!fseek(_M_file, __off, __whence))
      __ret = std::streampos(std::ftell(_M_file));
#endif

LFS significa Suporte a arquivos grandes .

Conclusão: Embora o padrão sugira uma definição streamoffque ostensivamente conflite com o requisito seekoffinvocado fseek, os designers de bibliotecas entendem que devem chamar a variante fseekque aceita toda a gama de compensações suportadas pelo sistema operacional.

Willis Blackburn
fonte
@ypnos Eu não reduzi o voto e acho esta resposta útil. Eu acho que alguém votou mal porque perdeu o objetivo. O problema não é que existam implementações sãs que ignoram o padrão a esse respeito; o problema é que o padrão precisa ser ignorado para que a implementação seja sã.
jceed2
6
The situation seems to be:- A situação é que a implementação não é permitido para não chamar fseekno seekoff. Deve chamar fseek, não é, o padrão diz que precisa. Eu posso argumentar que esta implementação é inválida. Eu acredito que não responde à pergunta. Och, encontrei llvm , ele chama fseeko.
KamilCuk 13/12/19
Assim como um FYI, o VC ++ solicita _fseeki64essa função; o que também parece violar o que o padrão diz.
ChrisMM
11
É o caso dos implementadores que estão percebendo o problema e ignorando o padrão. Estou feliz que eles fizeram, mas o padrão realmente precisa ser corrigido.
NathanOliver
11
Algumas pessoas estão adotando o padrão literalmente. Não é exigente que a implementação chame literalmente uma função chamada fseek. Em outros lugares, o padrão descreve algo como "como se estivesse ligando fseek(...)". Se se importasse tanto em ligar literalmente fseek, essa afirmação seria diferente. Sério, o que você faria se estivesse implementando uma biblioteca C ++? Você insistiria em chamar fseekcom os 32 bits inferiores de um deslocamento de arquivo de 64 bits, porque um documento solicita? Seus clientes agradeceriam por isso?
Willis Blackburn