Estou tentando criar uma função que geralmente será usada para determinar se existe um arquivo/diretório, se está dentro de um determinado caminho e se é do tipo especificado (S_ISREG, S_ISDIR, ...
Aqui estão as partes da fonte relativas a esta questão:
int checkExists(const char *name, void *func(int))) {
struct stat st ;
int returnValue = DOES_NOT_EXIST ;
BOOL isInSourceHierarchy, isInTargetHierarchy ;
if (stat(name, &st) != -1) {
returnValue = EXISTS ;
if (memcmp(name, top_dir, strlen(top_dir)))
returnValue |= IN_SOURCE_STRUCTURE ;
if (memcmp(name, tgt_dir, strlen(tgt_dir)))
returnValue |= IN_TARGET_STRUCTURE ;
if (func != NULL) {
if (objType == func(st.st_mode))
returnValue |= RIGHT_TYPE ;
}
}
return returnValue ;
}
. . .
if (S_ISREG(0)) {} // Yes, I know, I know. This is for demonstration only.
if (checkExists(old, S_ISREG)) {
// Do something
} else { // Old file doesn't exist
// Do something else
}
Ao tentar compilar isso, recebo:
linkStructure.c:642:31: error: ‘S_ISREG’ undeclared (first use in this function)
642 | if (checkExists(old, S_ISREG)) {
| ^~~~~~~
Como pode ser visto, não há reclamação sobre a macro usada conforme projetada, é claro. Então, minha pergunta é: existe uma maneira de referenciar a macro na minha fonte assim? Ou terei que basicamente emular a macro na minha função? (Suponho que poderia passar o tipo esperado em vez da função, mas, para maior clareza, gostaria de entender essa limitação.)
Diz
S_ISREG
que é indefinido porque o pré-processador não ignora os parênteses.#define FOO()
defineFOO()
, nãoFOO
.Além disso, sua função espera um ponteiro de função como parâmetro, mas as macros são símbolos apenas em tempo de compilação, você não pode usar seu endereço.
Mas você pode simplesmente envolvê-lo em uma função:
Agora você pode usá-lo como quiser:
E você mantém a flexibilidade do seu código original.
Não, você não pode fazer o que está tentando alcançar sem etapas extras.
S_ISREG
não existe e não há como saber o queS_ISREG(x)
se expande.Lembre-se de que as macros simplesmente realizam a substituição do token, o que significa que ele
S_ISREG(x)
é substituído por um código diferente antes mesmo de a análise começar (em teoria). Digamos que se expanda para algo como((x) & S_IFREG)
. Como você pode passar isso para a sua função? Você teria que criar uma função a partir dele.Alternativamente, você pode passar
S_IFREG
(que se expande para uma máscara) e fazer você mesmo a operação de bit apropriada.No entanto, você tem menos flexibilidade com esta segunda abordagem. Com a primeira abordagem, você poderia usar verificações mais complexas.
Mas você não pode fazer isso com a segunda abordagem.
A
S_ISREG
macro é uma macro semelhante a uma função, portanto, simplesmente usá-la comoS_ISREG
é inválido.Em vez disso, você precisará passar o sinalizador para o modo em questão, ou seja
S_IFREG
, executar uma máscara de bits com ele e o modo de arquivo.