You are currently browsing Claudio Matsuoka’s articles.
Palavras-chave: C, stdin, stdout, descritor, descriptor, inode, comparar, compare
Ao escrever filtros (programas que processam dados provenientes da entrada padrão e os escrevem na saída padrão) pode-se querer evitar que o arquivo de entrada seja o mesmo arquivo utilizado para saída. Um exemplo de um programa assim seria um conversor de formato: o que fazer caso o filtro seja invocado como
$ gif2png < tempfile > tempfile
ou ainda
$ sig2uns tempfile > tempfile
potencialmente corrompendo dados quando eles são lidos e processados em blocos?
Uma solução simples em sistemas que utilizam sistemas de arquivo similares aos do UNIX é comparar o número do inode e o dispositivo dos descritores de entrada e saída, sejam eles arquivos ou stdin/stdout. Isso pode ser implementado em C como:
fstat(ifd, &st);
st.st_mode &= S_IFMT;
if (st.st_mode != S_IFCHR && st.st_mode != S_IFBLK) {
dev = st.st_dev;
ino = st.st_ino;
}
fstat(ofd, &st);
st.st_mode &= S_IFMT;
if (st.st_dev == dev && st.st_ino == ino) {
/* entrada e saída são iguais */
return 1;
}
Isso é exatamente o que o programa “cat” faz. Se você experimentar fazer cat de um arquivo para ele mesmo, o resultado é:
$ cat a.out > a.out
cat: a.out: input file is output file
Finalmente, note que isso não vale para dispositivos de caractere ou bloco, como tratado no trecho de código acima.
Palavras-chave: C, macro, multi-statement, cpp, pré-processador, preprocessor
Com alguma freqüência é necessário de definir macros com múltiplos comandos (statements) que possam ser usados de forma sintaticamente equivalente a chamadas de função. Nesse caso, não basta definir uma seqüência como:
#define foo(x) a1(x); a2(x)
Isso seria desastroso após um if, por exemplo. Tampouco adiantaria delimitar o bloco com chaves, o que não funcionaria numa situação como:
if (y) foo(z); else return;
Como, então, podemos definir tais macros? A resposta é: utilizando expressões “do {…} while(0)”, cuja utilidade em outras situações é bastante duvidosa. Veja o exemplo:
#define foo(x) do { a1(x); a2(x); } while (0)
Definindo macros dessa forma, cumprimos nosso objetivo: apesar da declaração aparentemente estranha, seu uso é equivalente a uma chamada de função em qualquer caso, incluindo loops e condicionais.
É comum em utilitários que rodam em um terminal e escrevem na saída padrão (stdout) a existência de um parâmetro que permite redirecionar a saída para um arquivo (geralmente -o).
Uma maneira simples de implementar essa redireção é copiando o descritor do arquivo especificado para o descritor 1 (do stdout). Pode-se implementar isso da seguinte maneira, dentro do tratamento dos parâmetros de linha de comando:
case 'o':
ofd = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (ofd < 0) {
perror("open");
exit(1);
}
dup2(ofd, STDOUT_FILENO);
break;
onde optarg é o parâmetro passado para -o. Assim, o restante do código pode ser escrito sem se preocupar com o arquivo de saída, usando printf() normalmente para escrever em stdout.







Comentários Recentes