Qual é a diferença explícita entre as intenções Fortran (in, out, inout)?

StackOverflow https://stackoverflow.com/questions/1011604

  •  06-07-2019
  •  | 
  •  

Pergunta

Depois de procurar por um tempo nos livros, aqui em stackoverflow e na web em geral, eu descobri que é difícil encontrar uma explicação simples para as diferenças reais entre as intenções argumento Fortran. A maneira que eu entendi, é o seguinte:

  • intent(in) -. O argumento real é copiado para o argumento fictício na entrada
  • intent(out) -. As argumento fictício aponta para o argumento real (ambos apontam para o mesmo lugar na memória)
  • intent(inout) -. O argumento fictício é criado localmente, e depois copiado para o argumento real quando o procedimento for concluído

Se o meu entendimento é correto, então eu também quero saber por que ninguém nunca quer usar intent(out), desde o intent(inout) exige menos trabalho (sem cópia de dados).

Foi útil?

Solução

Intenções são apenas sugestões para o compilador, e você pode jogar essa informação de distância e violá-la. Intenções existe quase inteiramente para se certificar de que você só faz o que planejava fazer em uma sub-rotina. Um compilador pode optar por confiar em você e otimizar alguma coisa.

Isto significa que intent(in) não é passar por valor. Você ainda pode substituir o valor original.

program xxxx  
    integer i  
    i = 9  
    call sub(i)  
    print*,i ! will print 7 on all compilers I checked  
end  
subroutine sub(i)  
    integer,intent(in) :: i  
    call sub2(i)  
end  
subroutine sub2(i)  
    implicit none  
    integer i  
    i = 7  ! This works since the "intent" information was lost.  
end

program xxxx  
    integer i  
    i = 9  
    call sub(i)  
end  
subroutine sub(i)  
    integer,intent(out) :: i  
    call sub2(i)  
end  
subroutine sub2(i)  
    implicit none   
    integer i  
    print*,i ! will print 9 on all compilers I checked, even though intent was "out" above.  
end  

Outras dicas

  • intent(in) - parece que passe por valor (e alterações deste não são refletidas no código fora), mas é na passagem de fato por referência e mudá-lo é proibida pelo compilador. Mas ele pode ser alterado ainda.
  • intent(out) - passar de alguma forma por referência, na verdade, um argumento de retorno
  • intent(inout) -. Passagem por referência, em condições normais / out parâmetro

Use intent(out) se é está fora planície, para documentar o seu design. Não ligo para o muito pouco ganho de desempenho se houver. (Os comentários sugerem que há nenhum tão intent(in) é tecnicamente também passar por referência.)

Não está claro se as peças de perguntas do OP foram realmente respondeu. Além disso, certamente parece haver muita confusão e vários erros nas seguintes respostas / discussões que podem beneficiar de algumas clarificações.

A) A pergunta do OP Re

"então eu também quero saber por que ninguém nunca quer usar intenção (fora), uma vez que a intenção (inout) exige menos trabalho (sem cópia de dados)."

pode não ter respondido, ou pelo menos muito diretamente / corretamente.

Em primeiro lugar, ser claro os atributos Intent ter pelo menos dois propósitos:. "Segurança / higiene" e questões de "desempenho indireta" (não "de desempenho direta" questões)

1) Segurança / Higiene: Para auxiliar na produção de código "safe / sensível" com reduzida oportunidade de "baralhar as coisas" para cima. Assim, a intenção (In) não podem ser substituídos (pelo menos localmente, ou mesmo "globalmente" em algumas circunstâncias, ver abaixo).

Da mesma forma, Intenção (Out) exige que o Arg ser atribuída uma "resposta explícita", ajudando assim a reduzir resultados "lixo".

Por exemplo, na solução de, talvez, o problema mais comum em matemática computacional, isto é, o assim chamado "Ax = b problema", o "resultado directo / resposta" um está procurando os valores para o vetor x. Aqueles deve ser Intenção (Out) para assegurar x é atribuído uma resposta "explícito". Se x foi declarado como, por exemplo, Intenção (InOut) ou "nenhuma intenção", em seguida, Fortran seria atribuir x alguns "valores por defeito" (provavelmente "Zero" no modo de depuração, mas provavelmente "lixo" no modo de versão, Ser o que está em memória no local do ponteiro Args), e se o usuário não atribuir os valores corretos para x explicitamente, ele retornaria "lixo". A Intenção (Out) iria "lembrar / force" o utilizador a valores atribuir explicitamente para x, e eliminando, assim, este tipo de "(acidental) lixo".

Durante o processo de solução, seria (quase certamente) produzem o inverso da matriz A. O usuário pode desejar retornar esse inversa à chamada s / r no lugar de um, caso em que A deve ser Intenção (InOut) .

Em alternativa, o utilizador pode querer assegurar que não há mudanças são feitas para a matriz A ou o vector b, caso em que seria declarado Intenção (Na), e garantir, assim, que os valores críticos não são substituídos.

2 a) "Performance Indirecto" (e "segurança global / higiene"): Embora as intenções não são directamente para influenciar o desempenho, eles fazê-lo indiretamente. Notavelmente, certos tipos de otimização, e particularmente os Fortran construções puro e elementar, pode produzir desempenho muito melhor. Essas configurações normalmente exigem todos os Args ter a sua intenção de declarar explicitamente.

A grosso modo, se o compilador sabe de antemão a intenção de de todos Vars, então ele pode otimizar e "verificação de estupidez" o código com maior facilidade e eficácia.

Essencialmente, se alguém usa Pure etc construções, em seguida, com alta probabilidade, haverá uma "espécie de global de segurança / higiene", bem como, desde Pure / Elemental s / p de só pode chamar outro Pure / Elemental s / p de e assim não se pode chegar a uma situação do tipo indicado no exemplo "de o Glazer Guy".

Por exemplo, se Sub1 () é declarada como Pure, em seguida, Sub2 () deve também ser declarado como Pure, em seguida, ele será obrigado a declarar as intenções em todos os níveis, e assim o "garbage out" produzido nos " "o exemplo de o Glazer Guy não poderia acontecer. Ou seja, o código seria:

Pure subroutine sub_P(i)
    integer,intent(in) :: i
    call sub2_P(i)
end  subroutine sub_P

Pure subroutine sub2_P(i)
    implicit none
!        integer i          ! not permitted to omit Intent in a Pure s/p
    integer,intent(in) :: i
    i = 7   ! This WILL NOT WORK/HAPPEN, since Pure obviates the possibility of omitting Intent, and Intent(In) prohibits assignment ... so "i" remains "safe".
end  subroutine sub2_P

... na compilação, isso produziria algo como

"|| Erro: Manequim argumento 'i' com a intenção (IN) no contexto definição de variável (atribuição) em (1) |"

É claro, necessidade sub2 não ser Pure ter i declarado como Intent (In), que, mais uma vez iria proporcionar "segurança / higiene" se está procurando.

Observe que mesmo se eu foi declarada intenção (InOut) seria ainda falhar com pura. Ou seja:

Pure subroutine sub_P(i)
    integer,intent(in) :: i
    call sub2_P(i)
end  subroutine sub_P

Pure subroutine sub2_P(i)
    implicit none
    integer,intent(inOut) :: i
    i = 7   ! This WILL NOT WORK, since Pure obviates the possibility of "mixing" Intent's.
end  subroutine sub2_P

... na compilação, isso produziria algo como

"|| Erro: Manequim argumento 'i' com INTENT (IN) no contexto definição de variável (argumento real para INTENÇÃO = OUT / INOUT) em (1) | "

Assim, a dependência estrita ou de largura em construções Pure / Elemental irá garantir (principalmente) "segurança global / higiene".

Não será possível usar Pure / Elemental etc em todos os casos (por exemplo, muitas configurações de idioma misto, ou quando depender de bibliotecas externas além de seu controle, etc).

Ainda assim, o uso consistente de Intenções, e sempre que possível Pure etc, vai produzir muito benefício, e eliminar muita dor.

Pode-se simplesmente adquirir o hábito de declarar Intenções em todos os lugares o tempo todo quando é possível, seja pura ou não ... que é a prática de codificação recomendável.

... isto também traz à tona uma outra razão para a existência de ambos com a intenção (InOut) e Intenção (Out), uma vez que é pura deve ter a intenção de todos da Arg declarada, haverá algumas Args que são apenas para fora, enquanto outros são InOut (ou seja, seria difícil ter de pura, sem cada um de In, InOut, and out Intenções).

2 b) Os comentários do OP que esperam "melhorias de desempenho 'já que nenhuma cópia é necessária' indica um mal-entendido de Fortran e seu uso extensivo de passagem por referência. Passou por meio de referência, essencialmente, apenas os ponteiros são necessários, e de fato , é necessário muitas vezes, apenas o ponteiro para o primeiro elemento em uma matriz (além de alguns pouco escondido informações array).

De facto, alguma visão pode ser oferecido pelo considerando "Antigamente" (por exemplo, Fortran IV, 77, etc), quando se passa de uma matriz pode ter sido codificado como segue:

Real*8 A(1000)

Call Sub(A)

Subroutine Sub(A)

Real*8 A(1) ! this was workable since Fortran only passes the pointer/by ref to the first element of A(1000)
                ! modern Fortran may well throw a bounds check warning

Em Fortran moderna, o "equivalente" é declarar A como Real (DP) A (:) nos s / r (embora estritamente falando, existem várias configurações que o benefício de passar limites do array e declarando explicitamente com os limites , mas que seria uma longa digressão para outro dia).

Isto é, Fortran não passar por valor, nem "fazer cópias" para Args / manequim Vars. O A () na chamada s / r é o "mesmo A" que a utilizada no s / r (Claro, no s / r, pode-se fazer uma cópia de A () ou o que quer, o que criaria adicional trabalho / requisitos de espaço, mas isso é outro assunto).

É por esta razão principalmente que a intenção de não fazer diretamente o desempenho impacto, em grande medida, mesmo para grande variedade de Arg etc.

B) Em relação ao "passar por valor" confusão: Embora as várias resposta acima confirmam que o uso intenção é "não passar por valor", pode ser útil para esclarecer o assunto.

Ela pode ajudar a mudar o texto para "Intenção é sempre passar por referência". Este não é o mesmo que "não passar por valor", e é uma sutileza importante. Notavelmente, não só são Intenções "ByRef", Intenção pode impedir passagem por valor.

Embora existam / muito mais complexas configurações especiais (de idioma misto por exemplo etc do Fortran DLL), onde muita discussão adicional é necessária, na maior parte de "Fortran padrão", Args são passados ??por referência. A demonstração desta "Intenção sutileza" pode ser visto em uma simples extensão de "The Glazer Caras" exemplo, como:

subroutine sub(i)
    integer, intent(in) :: i, j
    integer, value     :: iV, jV
    call sub2(i)
    call sub3(i, j, jV, iV)
end
subroutine sub2(i)
    implicit none
    integer i
    i = 7  ! This works since the "intent" information was lost.
end
subroutine sub3(i, j, jV, iV)
    implicit none
    integer, value, Intent(In)          :: i    ! This will work, since passed in byRef, but used locally as byVal
    integer, value, Intent(InOut)       :: j    ! This will FAIL, since ByVal/ByRef collision with calling s/r,
                                                ! ||Error: VALUE attribute conflicts with INTENT(INOUT) attribute at (1)|
    integer, value, Intent(InOut)       :: iV   ! This will FAIL, since ByVal/ByRef collision with calling s/r,
                                                ! ... in spite of "byVal" in calling s/r
                                                ! ||Error: VALUE attribute conflicts with INTENT(INOUT) attribute at (1)|
    integer, value, Intent(Out)         :: jV   ! This will FAIL, since ByVal/ByRef collision with calling s/r
                                                ! ... in spite of "byVal" in calling s/r
                                                ! ||Error: VALUE attribute conflicts with INTENT(OUT) attribute at (1)|
    jV = -7
    iV = 7
end

Isto é, qualquer coisa com um aspecto "Out" para ele deve ser "ByRef" (pelo menos em configurações normais), pois a chamada s / r está esperando "ByRef". Assim, mesmo que declarar todas as s / r do Args como "valor", eles são "ByVal" apenas localmente (novamente em configurações padrão). Assim, qualquer tentativa da chamada s / r para retornar um Arg que é declarado como o valor com qualquer tipo de Fora Intenção, irá falhar devido à "colisão" dos estilos que passam.

Se ele deve ser "Out" ou "InOut" e "Valor", então não se pode usar Intenção:., Que é um pouco mais do que simplesmente dizer "não é passar por valor"

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