O código a seguir é compilado sem problemas:
int main() {
printf("Hi" "Bye");
}
No entanto, isso não compila:
int main() {
int test = 0;
printf("Hi" (test ? "Bye" : "Goodbye"));
}
Qual é o motivo disso?
c
string
syntax
concatenation
conditional-operator
José D.
fonte
fonte
"Hi"
e"Bye"
são strings literais , não strings como as usadas na biblioteca C padrão. Com literais de string , o compilador irá concatenar"H\0i" "B\0ye"
. Não é o mesmo comsprintf(buf,"%s%s", "H\0i" "B\0ye");
a (some_condition ? + : - ) b
printf("Hi" ("Bye"));
funciona - não requer o operador ternário; o parêntese é suficiente (emboraprintf("Hi" test ? "Bye" : "Goodbye")
também não seja compilado). Há apenas um número limitado de tokens que podem seguir um literal de string. Vírgula,
, colchete aberto, colchete[
fechado]
(como em1["abc"]
- e sim, é horrível), colchete redondo)
, colchete fechado}
(em um inicializador ou contexto semelhante) e ponto-e-vírgula;
são legítimos (e outro literal de string); Não tenho certeza se há outros.Respostas:
De acordo com o padrão C (5.1.1.2 fases de tradução)
E só depois disso
Nesta construção
não há tokens literais de string adjacentes. Portanto, esta construção é inválida.
fonte
(test ? "Bye" : "Goodbye")
evaulate para qualquer um dos literais de string essencialmente fazendo"Hi" "Bye"
ou"Hi Goodbye"
? (minha pergunta é respondida nas outras respostas)De acordo com o padrão C11, capítulo §5.1.1.2, concatenação de literais de string adjacentes:
acontece na fase de tradução . Por outro lado:
envolve o operador condicional, que é avaliado em tempo de execução . Portanto, em tempo de compilação, durante a fase de tradução, não há literais de string adjacentes presentes, portanto, a concatenação não é possível. A sintaxe é inválida e, portanto, relatada por seu compilador.
Para elaborar um pouco sobre a parte porque , durante a fase de pré-processamento, os literais de string adjacentes são concatenados e representados como um único literal de string (token). O armazenamento é alocado de acordo e o literal de string concatenado é considerado como uma entidade única (um literal de string).
Por outro lado, no caso de concatenação em tempo de execução, o destino deve ter memória suficiente para conter o literal de string concatenado , caso contrário, não haverá nenhuma maneira de acessar a saída concatenada esperada . Agora, no caso de strings literais , eles já estão alocados de memória em tempo de compilação e não pode ser estendido para caber em qualquer entrada de mais de entrada em ou anexado ao conteúdo original. Em outras palavras, não haverá como o resultado concatenado ser acessado (apresentado) como um único literal de string . Portanto, essa construção é inerentemente incorreta.
Apenas para sua informação, para concatenação de string em tempo de execução ( não literais ), temos a função de biblioteca
strcat()
que concatena duas strings . Observe, a descrição menciona:Portanto, podemos ver que
s1
é uma string , não uma string literal . No entanto, como o conteúdo des2
não é alterado de forma alguma, pode muito bem ser um literal de string .fonte
strcat
: o array de destino deve ser longo o suficiente para receber os caracteres des2
mais um terminador nulo após os caracteres já presentes lá.A concatenação de literal de string é executada pelo pré-processador em tempo de compilação. Não há como essa concatenação reconhecer o valor de
test
, que não é conhecido até que o programa seja realmente executado. Portanto, esses literais de string não podem ser concatenados.Como o caso geral é que você não teria uma construção como essa para valores conhecidos em tempo de compilação, o padrão C foi projetado para restringir o recurso de autocacatenação ao caso mais básico: quando os literais estão literalmente lado a lado .
Mas mesmo que essa restrição não seja expressa dessa forma, ou se a restrição for construída de forma diferente, seu exemplo ainda seria impossível de realizar sem tornar a concatenação um processo de tempo de execução. E, para isso, temos as funções de biblioteca como
strcat
.fonte
Porque C não tem
string
tipo. Literais de string são compilados emchar
arrays, referenciados por umchar*
ponteiro.C permite que literais adjacentes sejam combinados em tempo de compilação , como em seu primeiro exemplo. O próprio compilador C tem algum conhecimento sobre strings. Mas essas informações não estão presentes no tempo de execução e , portanto, a concatenação não pode acontecer.
Durante o processo de compilação, seu primeiro exemplo é "traduzido" para:
Observe como as duas strings são combinadas em um único array estático pelo compilador, antes que o programa seja executado.
No entanto, seu segundo exemplo é "traduzido" para algo assim:
Deve ficar claro por que isso não compila. O operador ternário
?
é avaliado em tempo de execução, não em tempo de compilação, quando as "strings" não existem mais como tais, mas apenas comochar
matrizes simples , referenciadas porchar*
ponteiros. Ao contrário dos literais de string adjacentes , os ponteiros char adjacentes são simplesmente um erro de sintaxe.fonte
static const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
serstatic const char *char_ptr_1 = "HiBye";
e da mesma forma para o resto dos ponteiros?static const char *char_ptr_1 = "HiBye";
o compilador traduz a linha parastatic const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
, então não, ela não deve ser escrita "como uma string". Como diz a resposta, as strings são compiladas para uma matriz de caracteres, e se você atribuísse uma matriz de caracteres em sua forma mais "bruta", você usaria uma lista de caracteres separada por vírgulas, exatamente comostatic const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
static const char str[] = {'t', 'e', 's', 't', '\0'};
seja o mesmo questatic const char str[] = "test";
, nãostatic const char* ptr = "test";
é o mesmo que . O primeiro é válido e irá compilar, mas o último é inválido e faz o que você espera.static const char* ptr = {'t', 'e', 's', 't', '\0'};
Se você realmente deseja que ambas as ramificações produzam constantes de string de tempo de compilação a serem escolhidas em tempo de execução, você precisará de uma macro.
fonte
Seu código usando o operador ternário escolhe condicionalmente entre dois literais de string. Não importa a condição conhecida ou desconhecida, isso não pode ser avaliado em tempo de compilação, portanto, não pode ser compilado. Mesmo esta declaração
printf("Hi" (1 ? "Bye" : "Goodbye"));
não compilaria. O motivo é explicado em detalhes nas respostas acima. Outra possibilidade de fazer tal declaração usando o operador ternário válido para compilar também envolveria uma tag de formato e o resultado da declaração do operador ternário formatado como argumento adicional paraprintf
. Mesmo assim, aprintf()
impressão daria a impressão de "ter concatenado" essas strings apenas no tempo de execução e logo no início .fonte
printf
não requer um especificador de formato; se apenas a concatenação fosse feita em tempo de compilação (o que não é), o uso de printf pelo OP seria válido.printf()
exigiria uma tag de formatação, o que não é absolutamente verdade. Corrigido!Em
printf("Hi" "Bye");
você tem dois arrays consecutivos de char que o compilador pode transformar em um único array.Em
printf("Hi" (test ? "Bye" : "Goodbye"));
você tem uma matriz seguida por um ponteiro para char (uma matriz convertida em um ponteiro para seu primeiro elemento). O compilador não pode mesclar uma matriz e um ponteiro.fonte
Para responder à pergunta - eu iria para a definição de printf. A função printf espera const char * como argumento. Qualquer string literal como "Hi" é um const char *; no entanto, uma expressão como
(test)? "str1" : "str2"
NÃO é const char * porque o resultado de tal expressão é encontrado apenas em tempo de execução e, portanto, é indeterminado em tempo de compilação, um fato que devidamente faz com que o compilador reclame. Por outro lado - isso funciona perfeitamente bemprintf("hi %s", test? "yes":"no")
fonte
(test)? "str1" : "str2"
NÃO é umconst char*
... Claro que é! Não é uma expressão constante, mas seu tipo éconst char *
. Seria perfeitamente normal escreverprintf(test ? "hi " "yes" : "hi " "no")
. O problema do OP não tem nada a ver comprintf
,"Hi" (test ? "Bye" : "Goodbye")
é um erro de sintaxe, não importa qual seja o contexto da expressão.Isso não compila porque a lista de parâmetros para a função printf é
e
não cabe na lista de parâmetros.
O gcc tenta dar sentido a isso imaginando que
é uma lista de parâmetros e reclama que "Hi" não é uma função.
fonte
printf()
lista de argumentos, mas isso é porque a expressão não é válida em qualquer lugar - não apenas em umaprintf()
lista de argumentos. Em outras palavras, você escolheu um motivo muito especializado para o problema; o problema geral é que isso"Hi" (
não é válido em C, muito menos em uma chamada paraprintf()
. Eu sugiro que você exclua esta resposta antes que ela seja rejeitada.