Ponto de entrada - Entry point

Exemplo da função principal, em C #.
Como isso pode aparecer no código-fonte C # . Diferentes partes são rotuladas para referência.Main()

Na programação de computadores , um ponto de entrada é um ponto em um programa onde a execução de um programa começa e onde o programa tem acesso aos argumentos da linha de comando .

Para iniciar a execução de um programa , o carregador ou sistema operacional passa o controle para seu ponto de entrada. (Durante a inicialização , o próprio sistema operacional é o programa). Isso marca a transição do tempo de carregamento (e tempo de link dinâmico , se houver) para o tempo de execução .

Para alguns sistemas operacionais e linguagens de programação , o ponto de entrada está em uma biblioteca de tempo de execução , um conjunto de funções de suporte para a linguagem. O código da biblioteca inicializa o programa e então passa o controle para o programa apropriado. Em outros casos, o programa pode inicializar a própria biblioteca de tempo de execução.

Em sistemas simples, a execução começa na primeira instrução, o que é comum em linguagens interpretadas , formatos executáveis simples e carregadores de boot . Em outros casos, o ponto de entrada está em algum outro endereço de memória conhecido que pode ser um endereço absoluto ou endereço relativo ( deslocamento ).

Como alternativa, a execução de um programa pode começar em um ponto nomeado, com um nome convencional definido pela linguagem de programação ou sistema operacional ou em um nome especificado pelo chamador. Em muitas linguagens da família C , essa é uma função chamada main; como resultado, o ponto de entrada costuma ser conhecido como a função principal .

Em linguagens JVM , como Java, o ponto de entrada é um método estático denominado main; em linguagens CLI , como C #, o ponto de entrada é um método estático denominado Main.

Uso

Os pontos de entrada se aplicam ao código-fonte e aos arquivos executáveis . No entanto, no desenvolvimento de software do dia-a-dia , os programadores especificam os pontos de entrada apenas no código-fonte, o que os torna muito mais conhecidos. Os pontos de entrada nos arquivos executáveis ​​dependem da interface binária do aplicativo (ABI) do sistema operacional real e são gerados pelo compilador ou vinculador (se não corrigidos pela ABI). Outros arquivos de objeto vinculados também podem ter pontos de entrada, que são usados ​​posteriormente pelo vinculador ao gerar pontos de entrada de um arquivo executável.

Os pontos de entrada são capazes de transmitir argumentos de comando, variáveis ​​ou outras informações como uma variável local usada pelo Main()método. Desta forma, opções específicas podem ser definidas na execução do programa e então interpretadas pelo programa. Muitos programas usam isso como uma forma alternativa de definir configurações diferentes ou executar uma variedade de ações usando um único programa.

Contemporâneo

Na maioria das linguagens de programação e sistemas operacionais populares de hoje, um programa de computador geralmente tem apenas um único ponto de entrada .

Em programas C , C ++ , D , Zig , Rust e Kotlin , esta é uma função chamada main; em Java , é um método estático denominado main(embora a classe deva ser especificada no momento da invocação) e em C # é um método estático denominado Main.

Em muitos dos principais sistemas operacionais, o formato executável padrão tem um único ponto de entrada. No Executable and Linkable Format (ELF), usado em Unix e sistemas semelhantes ao Unix, como Linux , o ponto de entrada é especificado no e_entrycampo do cabeçalho ELF. Na GNU Compiler Collection (gcc), o ponto de entrada usado pelo vinculador é o _startsímbolo. Da mesma forma, no formato Portable Executable , usado no Microsoft Windows , o ponto de entrada é especificado pelo AddressOfEntryPointcampo, que é herdado de COFF . Em arquivos COM , o ponto de entrada está no deslocamento fixo de 0100h.

Uma exceção ao paradigma de ponto de entrada único é o Android . Os aplicativos Android não possuem um único ponto de entrada - não há nenhuma mainfunção especial . Em vez disso, eles têm componentes essenciais (atividades e serviços) que o sistema pode carregar e executar conforme necessário.

Uma técnica usada ocasionalmente é o binário fat , que consiste em vários executáveis ​​para diferentes destinos empacotados em um único arquivo. Mais comumente, isso é implementado por um único ponto de entrada geral, que é compatível com todos os destinos e ramificações para o ponto de entrada específico do destino. Técnicas alternativas incluem o armazenamento de executáveis ​​separados em garfos separados , cada um com seu próprio ponto de entrada, que é então selecionado pelo sistema operacional.

Histórico

Historicamente, e em alguns sistemas legados contemporâneos , como VMS e OS / 400 , os programas de computador têm uma infinidade de pontos de entrada , cada um correspondendo às diferentes funcionalidades do programa. A maneira usual de denotar pontos de entrada, como usados ​​em todo o sistema em VMS e em programas PL / I e MACRO , é anexá-los ao final do nome da imagem executável , delimitado por um cifrão ($), por exemplo directory.exe$make.

O computador Apple I também usou isso até certo ponto. Por exemplo, um ponto de entrada alternativo no BASIC do Apple I manteria o programa BASIC útil quando o botão de reinicialização fosse pressionado acidentalmente.

Ponto de saída

Em geral, os programas podem ser encerrados a qualquer momento, retornando ao sistema operacional ou travando . Os programas em linguagens interpretadas retornam o controle ao interpretador, mas os programas em linguagens compiladas devem retornar ao sistema operacional, caso contrário, o processador simplesmente continuará executando além do final do programa, resultando em um comportamento indefinido .

Normalmente, não há um único ponto de saída especificado em um programa. No entanto, em outros casos, os tempos de execução garantem que os programas sempre terminem de maneira estruturada por meio de um único ponto de saída, o que é garantido, a menos que o próprio tempo de execução trave; isso permite que o código de limpeza seja executado, como atexitmanipuladores. Isso pode ser feito exigindo que os programas sejam encerrados retornando da função principal, chamando uma função de saída específica ou pelo tempo de execução que captura exceções ou sinais do sistema operacional.

Linguagens de programação

Em muitas linguagens de programação, a mainfunção é onde um programa inicia sua execução. Ele permite a organização de alto nível da funcionalidade do programa e, normalmente, tem acesso aos argumentos de comando fornecidos ao programa quando ele foi executado.

A função principal é geralmente a primeira função escrita pelo programador que é executada quando um programa é iniciado e é chamada diretamente da inicialização específica do sistema contida no ambiente de tempo de execução ( crt0 ou equivalente). No entanto, algumas linguagens podem executar funções escritas pelo usuário antes das execuções principais, como os construtores de objetos globais C ++ .

Em outras linguagens, principalmente em muitas linguagens interpretadas , a execução começa na primeira instrução do programa.

Uma lista não exaustiva de linguagens de programação segue, descrevendo sua maneira de definir o ponto de entrada principal:

APL

Em APL , quando um espaço de trabalho é carregado, o conteúdo da variável "quad LX" (expressão latente) é interpretado como uma expressão APL e executado.

C e C ++

Em C e C ++ , o protótipo de função da função principal se parece com um dos seguintes:

int main(void);
int main();

int main(int argc, char **argv);
int main(int argc, char *argv[]);
int main(int argc, char **argv, char **env);

// more specifically in C
// NOT according to the ISO C standard 5.1.2.2.1
// BUT in embedded programming depending on the µC, this form is also used
void main (void);

A função principal parece um ponto de entrada para programadores de aplicativos (o ponto de entrada do aplicativo ou o ponto de entrada principal). A programação do sistema revela mais informações sobre o programa e especifica o ponto de entrada em outro lugar (no procedimento de inicialização ou no vetor de interrupção de reinicialização para programas independentes).

Os parâmetros argc , contagem de argumento , e argv, vector argumento , respectivamente dar o número e os valores do programa argumentos de linha de comando . Os nomes de argce argvpodem ser qualquer identificador válido em C, mas é uma convenção comum usar esses nomes. Em C ++, os nomes devem ser interpretados literalmente e o "vazio" na lista de parâmetros deve ser omitido, se a conformidade estrita for desejada. Outros formatos dependentes de plataforma também são permitidos pelos padrões C e C ++, exceto que em C ++ o tipo de retorno deve ser sempre int; por exemplo, Unix (embora não POSIX.1 ) e Windows têm um terceiro argumento que fornece o ambiente do programa , de outra forma acessível através getenvde stdlib.h:

int main(int argc, char **argv, char **envp);

Os sistemas operacionais baseados em Darwin , como o macOS , têm um quarto parâmetro contendo informações arbitrárias fornecidas pelo sistema operacional, como o caminho para o binário em execução:

int main(int argc, char **argv, char **envp, char **apple);

O valor retornado da função principal torna-se o status de saída do processo, embora o padrão C apenas atribua significado específico a dois valores: EXIT_SUCCESS(tradicionalmente 0) e EXIT_FAILURE. O significado de outros valores de retorno possíveis é definido pela implementação. Caso um valor de retorno não seja definido pelo programador, um implícito return 0;no final da main()função é inserido pelo compilador; esse comportamento é exigido pelo padrão C ++.

É garantido que argcnão é negativo e que argv[argc]é um ponteiro nulo . Por convenção, os argumentos da linha de comando especificados por argce argvincluem o nome do programa como o primeiro elemento se argcfor maior que 0; se um usuário digitar o comando " rm file", o shell inicializará o rmprocesso com argc = 2e argv = {"rm", "file", NULL}. Como argv[0]é o nome sob o qual os processos aparecem ps, topetc., alguns programas, como daemons ou aqueles em execução em um interpretador ou máquina virtual (onde argv[0]seria o nome do executável do host), podem escolher alterar seu argv para fornecer um mais descritivo argv[0], geralmente por meio da execchamada de sistema.

A main()função é especial; normalmente, todo programa C e C ++ deve defini-lo exatamente uma vez.

Se declarado, main()deve ser declarado como se tivesse ligação externa; não pode ser declarado staticou inline.

Em C ++, main()deve estar no namespace global (ou seja ::main), não pode ser sobrecarregado e não pode ser uma função de membro , embora o nome não seja reservado de outra forma e pode ser usado para funções de membro, classes, enumerações ou funções de não membro em outros namespaces. Em C ++ (ao contrário de C) main()não pode ser chamado recursivamente e não pode ter seu endereço obtido.

C #

Ao executar um programa escrito em C # , o CLR procura um método estático marcado com a .entrypointdiretiva IL, que não aceita nenhum argumento ou um único argumento do tipo string[]e tem um tipo de retorno de voidou int, e o executa.

static void Main();
static void Main(string[] args);
static int Main();
static int Main(string[] args);

Os argumentos da linha de comando são transmitidos args, de forma semelhante à forma como é feito em Java. Para versões de Main()retorno de um número inteiro, semelhante a C e C ++, ele é passado de volta ao ambiente como o status de saída do processo.

Desde C # 7.1, existem mais quatro assinaturas possíveis do ponto de entrada, que permitem a execução assíncrona no Main()Método.

static Task Main()
static Task<int> Main()
static Task Main(string[])
static Task<int> Main(string[])

Os tipos Taske Task<int>são os equivalentes assíncronos de voide int.

Limpar

Clean é uma linguagem de programação funcional baseada na reescrita de gráficos. O nó inicial é nomeado Starte é do tipo *World -> *Worldse muda o mundo ou algum tipo fixo se o programa só imprime o resultado após a redução Start .

Start :: *World -> *World
Start world = startIO ...

Ou ainda mais simples

Start :: String
Start = "Hello, world!"

Um diz ao compilador qual opção usar para gerar o arquivo executável.

Lisp Comum

ANSI Common Lisp não define uma função principal; em vez disso, o código é lido e avaliado de cima para baixo em um arquivo de origem. No entanto, o código a seguir emulará uma função principal.

(defun hello-main ()
  (format t "Hello World!~%"))

(hello-main)

D

Em D , o protótipo da função principal se parece com um dos seguintes:

void main();
void main(string[] args);
int main();
int main(string[] args);

Os argumentos da linha de comando são transmitidos args, de forma semelhante à forma como é feito em C # ou Java. Para versões de main()retorno de um número inteiro, semelhante a C e C ++, ele é passado de volta ao ambiente como o status de saída do processo.

FORTRAN

FORTRAN não tem uma sub-rotina ou função principal. Em vez disso, uma PROGRAMinstrução como a primeira linha pode ser usada para especificar que uma unidade de programa é um programa principal, conforme mostrado abaixo. A PROGRAMinstrução não pode ser usada para chamadas recursivas.

      PROGRAM HELLO
      PRINT *, "Cint!"
      END PROGRAM HELLO

Algumas versões do Fortran, como aquelas no IBM System / 360 e mainframes sucessores, não suportam a instrução PROGRAM. Muitos compiladores de outros fabricantes de software permitirão que um programa fortran seja compilado sem uma instrução PROGRAM. Nestes casos, qualquer módulo que tenha qualquer instrução sem comentário em que nenhuma instrução SUBROUTINE, FUNCTION ou BLOCK DATA ocorra, é considerado o programa Principal.

MOSQUITO

Usando GNAT , o programador não precisa escrever uma função chamada main; um arquivo de origem contendo um único subprograma pode ser compilado para um executável. O fichário, entretanto, criará um pacote ada_main, que conterá e exportará uma função principal estilo C.

Vai

Na linguagem de programação Go , a execução do programa começa com a mainfunção dopackage main

package main

import "fmt"

func main() {
 fmt.Println("Hello, World!")
}

Não há como acessar argumentos ou um código de retorno fora da biblioteca padrão do Go. Eles podem ser acessados ​​via os.Argse os.Exitrespectivamente, os quais estão incluídos no "os"pacote.

Haskell

Um programa Haskell deve conter um nome mainvinculado a um valor de tipo IO t, para algum tipo t; que geralmente é IO (). IOé uma mônada , que organiza os efeitos colaterais em termos de código puramente funcional . O mainvalor representa o cálculo de efeitos colaterais feito pelo programa. O resultado do cálculo representado por mainé descartado; é por isso que maingeralmente tem tipo IO (), que indica que o tipo do resultado do cálculo é (), o tipo de unidade , que não contém nenhuma informação.

main :: IO ()
main = putStrLn "Hello, World!"

Os argumentos da linha de comando não são fornecidos para main; eles devem ser buscados usando outra ação IO, como System.Environment.getArgs.

Java

Os programas Java começam a ser executados no método principal de uma classe, que tem um dos seguintes títulos de método :

public static void main(String[] args)
public static void main(String... args)
public static void main(String args[])

Os argumentos da linha de comando são transmitidos args. Como em C e C ++, o nome " main()" é especial. Os principais métodos de Java não retornam um valor diretamente, mas um pode ser passado usando o System.exit()método.

Ao contrário de C, o nome do programa não está incluído em args, porque é o nome da classe que contém o método principal, portanto, já é conhecido. Também ao contrário de C, o número de argumentos não precisa ser incluído, uma vez que os arrays em Java têm um campo que controla quantos elementos existem.

A função principal deve ser incluída em uma classe. Isso ocorre porque em Java tudo deve estar contido em uma classe. Por exemplo, um programa hello world em Java pode ser parecido com:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

Para executar este programa, deve-se chamar java HelloWorldno diretório onde existe o arquivo de classe compilado HelloWorld.class). Como alternativa, os arquivos JAR executáveis usam um arquivo de manifesto para especificar o ponto de entrada de uma maneira que seja independente do sistema de arquivos da perspectiva do usuário.

No FMSLogo , os procedimentos quando carregados não são executados. Para executá-los, é necessário utilizar este código:

to procname
 ...                 ; Startup commands (such as print [Welcome])
end
make "startup [procname]

A variável startupé usada para a lista de inicialização de ações, mas a convenção é que isso chama outro procedimento que executa as ações. Esse procedimento pode ter qualquer nome.

OCaml

OCaml não tem mainfunção. Os programas são avaliados de cima para baixo.

Os argumentos da linha de comando estão disponíveis em uma matriz chamada Sys.argve o status de saída é 0 por padrão.

Exemplo:

print_endline "Hello World"

Pascal

Em Pascal , o procedimento principal é o único bloco sem nome no programa. Como os programas Pascal definem procedimentos e funções em uma ordem ascendente mais rigorosa do que os programas C, C ++ ou Java, o procedimento principal geralmente é o último bloco do programa. Pascal não tem um significado especial para o nome " main" ou qualquer nome semelhante.

program Hello(Output);
begin
  writeln('Hello, world!');
end.

Os argumentos da linha de comando são contados ParamCounte acessíveis como strings por ParamStr(n), com n entre 0 e ParamCount.

As versões do Pascal que suportam unidades ou módulos também podem conter um bloco sem nome em cada um, que é usado para inicializar o módulo. Esses blocos são executados antes que o ponto de entrada do programa principal seja chamado.

Perl

Em Perl , não há função principal. As instruções são executadas de cima para baixo.

Os argumentos da linha de comando estão disponíveis na matriz especial @ARGV. Ao contrário de C, @ARGVnão contém o nome do programa, que é $0.

PHP

O PHP não tem uma função "principal". A partir da primeira linha de um script PHP, qualquer código não encapsulado por um cabeçalho de função é executado assim que é visto.

Pique

Em Pike, a sintaxe é semelhante à de C e C ++. A execução começa às main. A argcvariável " " mantém o número de argumentos passados ​​para o programa. A argvvariável " " contém o valor associado aos argumentos passados ​​para o programa.

Exemplo:

 int main(int argc, array(string) argv)

Pitão

Os programas Python são avaliados de cima para baixo, como é comum em linguagens de script: o ponto de entrada é o início do código-fonte. Como as definições devem preceder o uso, os programas são normalmente estruturados com definições na parte superior e o código a ser executado na parte inferior (sem recuo), semelhante ao código para um compilador de uma passagem , como em Pascal.

Alternativamente, um programa pode ser estruturado com uma mainfunção explícita contendo o código a ser executado quando um programa é executado diretamente, mas que também pode ser invocado importando o programa como um módulo e chamando a função. Isso pode ser feito pelo seguinte idioma, que depende da variável interna __name__sendo definida __main__quando um programa é executado, mas não quando é importado como um módulo (neste caso, é definido como o nome do módulo); existem muitas variantes desta estrutura:

import sys

def main(argv):
    n = int(argv[1])
    print(n + 1)

if __name__ == '__main__':
    sys.exit(main(sys.argv))

Nesse idioma, a chamada para o ponto de entrada nomeado mainé explícita e a interação com o sistema operacional (recebendo os argumentos, chamando a saída do sistema) é feita explicitamente por chamadas de biblioteca, que são tratadas pelo tempo de execução do Python. Isso contrasta com C, onde isso é feito implicitamente pelo tempo de execução, com base na convenção.

QB64

A linguagem QB64 não possui função principal, o código que não está dentro de uma função ou sub-rotina é executado primeiro, de cima para baixo:

print "Hello World! a =";
a = getInteger(1.8d): print a

function getInteger(n as double)
    getInteger = int(n)
end function

Os argumentos da linha de comando (se houver) podem ser lidos usando a função COMMAND $:

dim shared commandline as string
commandline = COMMAND$

'Several space-separated command line arguments can be read using COMMAND$(n)
commandline1 = COMMAND$(2)

Rubi

Em Ruby , não existe uma função principal distinta. Fora Em vez disso, o código escrito de qualquer class .. endou module .. endescopo é executado no contexto de um especial " main" objeto. Este objeto pode ser acessado usando self:

irb(main):001:0> self
=> main

Possui as seguintes propriedades:

irb(main):002:0> self.class
=> Object
irb(main):003:0> self.class.ancestors
=> [Object, Kernel, BasicObject]

Métodos definidos fora de um escopo classou modulesão definidos como métodos privados do mainobjeto " ". Como a classe de " main" é Object, esses métodos se tornam métodos privados de quase todos os objetos:

irb(main):004:0> def foo
irb(main):005:1>   42
irb(main):006:1> end
=> nil
irb(main):007:0> foo
=> 42
irb(main):008:0> [].foo
NoMethodError: private method `foo' called for []:Array
	from (irb):8
	from /usr/bin/irb:12:in `<main>'
irb(main):009:0> false.foo
NoMethodError: private method `foo' called for false:FalseClass
	from (irb):9
	from /usr/bin/irb:12:in `<main>'

O número e os valores dos argumentos da linha de comando podem ser determinados usando a ARGVmatriz constante:

$ irb /dev/tty foo bar

tty(main):001:0> ARGV
ARGV
=> ["foo", "bar"]
tty(main):002:0> ARGV.size
ARGV.size
=> 2

O primeiro elemento ARGV, ARGV[0]contém o primeiro argumento de linha de comando, não o nome do programa executado, como em C. O nome do programa está disponível usando $0ou $PROGRAM_NAME.

Semelhante ao Python, pode-se usar:

if __FILE__ == $PROGRAM_NAME
  # Put "main" code here
end

para executar algum código apenas se seu arquivo foi especificado na rubychamada.

Ferrugem

No Rust, o ponto de entrada de um programa é uma função chamada main. Normalmente, essa função está situada em um arquivo chamado main.rsou lib.rs.

// In `main.rs`
fn main() {
    println!("Hello, World!");
}

Além disso, a partir do Rust 1.26.0, a função principal pode retornar um Result:

fn main() -> Result<(), std::io::Error> {
    println!("Hello, World!");

    Ok(())  // Return a type `Result` of value `Ok` with the content `()`, i.e. an empty tuple.
}

Rápido

Quando executado em um Xcode Playground, o Swift se comporta como uma linguagem de script, executando instruções de cima para baixo; o código de nível superior é permitido.

// HelloWorld.playground

let hello = "hello"
let world = "world"

let helloWorld = hello + " " + world

print(helloWorld) // hello world

Cacau - e Cocoa Touch baseados em aplicações escritas em Swift normalmente são inicializados com os @NSApplicationMaine @UIApplicationMainatributos, respectivamente. Esses atributos são equivalentes em sua finalidade ao main.marquivo em projetos Objective-C : eles declaram implicitamente a mainfunção que chama UIApplicationMain(_:_:_:_:)e cria uma instância de UIApplication. O código a seguir é a maneira padrão de inicializar um aplicativo iOS baseado em Cocoa Touch e declarar seu delegado de aplicativo.

// AppDelegate.swift

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        return true
    }
    
}

Visual básico

No Visual Basic , quando um projeto não contém formulários, o objeto de inicialização pode ser o Main()procedimento. A Command$função pode ser usada opcionalmente para acessar a parte do argumento da linha de comando usada para iniciar o programa:

Sub Main()
    Debug.Print "Hello World!"
    MsgBox "Arguments if any are: " & Command$
End Sub

Xojo

No Xojo , existem dois tipos de projeto diferentes, cada um com um ponto de entrada principal diferente. Os aplicativos de desktop (GUI) começam com o App.Openevento do Applicationobjeto do projeto . Os aplicativos de console começam com o App.Runevento do ConsoleApplicationobjeto do projeto . Em ambos os casos, a função principal é gerada automaticamente e não pode ser removida do projeto.

Veja também

Referências

links externos