ternario operador ejemplo condicional c string concatenation

c - ejemplo - operador ternario php



¿Por qué C no permite concatenar cadenas cuando se usa el operador ternario? (9)

El siguiente código se compila sin problemas:

int main() { printf("Hi" "Bye"); }

Sin embargo, esto no compila:

int main() { int test = 0; printf("Hi" (test ? "Bye" : "Goodbye")); }

¿Cuál es la razón para eso?


¿Cuál es la razón para eso?

Su código que usa el operador ternario elige condicionalmente entre dos literales de cadena. No importa la condición conocida o desconocida, esto no se puede evaluar en tiempo de compilación, por lo que no se puede compilar. Incluso esta declaración printf("Hi" (1 ? "Bye" : "Goodbye")); No compilaría. La razón se explica en profundidad en las respuestas anteriores. Otra posibilidad de hacer una declaración de este tipo utilizando un operador ternario válido para compilar , también implicaría una etiqueta de formato y el resultado de la declaración del operador ternario formateada como argumento adicional para printf . Incluso entonces, la impresión printf() daría la impresión de "haber concatenado" esas cadenas solo en, y tan pronto como en tiempo de ejecución .

#include <stdio.h> int main() { int test = 0; printf("Hi %s/n", (test ? "Bye" : "Goodbye")); //specify format and print as result }


De acuerdo con el Estándar C (5.1.1.2 Fases de traducción)

1 La precedencia entre las reglas de sintaxis de traducción se especifica mediante las siguientes fases. 6)

  1. Los tokens literales de cadena adyacentes se concatenan.

Y solo después de eso

  1. Los caracteres de espacio en blanco que separan las fichas ya no son significativos. Cada token de preprocesamiento se convierte en un token. Los tokens resultantes se analizan sintáctica y semánticamente y se traducen como una unidad de traducción .

En esta construccion

"Hi" (test ? "Bye" : "Goodbye")

no hay tokens literales de cadena adyacentes. Entonces esta construcción no es válida.


En printf("Hi" "Bye"); tiene dos matrices consecutivas de caracteres que el compilador puede convertir en una sola matriz.

En printf("Hi" (test ? "Bye" : "Goodbye")); tiene una matriz seguida de un puntero a char (una matriz convertida en un puntero a su primer elemento). El compilador no puede fusionar una matriz y un puntero.


Esto no se compila porque la lista de parámetros para la función printf es

(const char *format, ...)

y

("Hi" (test ? "Bye" : "Goodbye"))

no se ajusta a la lista de parámetros.

gcc intenta darle sentido imaginando que

(test ? "Bye" : "Goodbye")

es una lista de parámetros y se queja de que "Hola" no es una función.


La concatenación literal de cadenas la realiza el preprocesador en tiempo de compilación. No hay forma de que esta concatenación sea consciente del valor de la test , que no se conoce hasta que el programa realmente se ejecuta. Por lo tanto, estos literales de cadena no se pueden concatenar.

Debido a que el caso general es que no tendría una construcción como esta para valores conocidos en tiempo de compilación, el estándar C fue diseñado para restringir la función de autoconcatenación al caso más básico: cuando los literales están literalmente uno al lado del otro .

Pero incluso si no estableciera esta restricción de esa manera, o si la restricción se construyera de manera diferente, su ejemplo aún sería imposible de realizar sin convertir la concatenación en un proceso de tiempo de ejecución. Y, para eso, tenemos las funciones de biblioteca como strcat .


Para responder a la pregunta, iría a la definición de printf. La función printf espera const char * como argumento. Cualquier cadena literal como "Hola" es un const char *; Sin embargo, una expresión como (test)? "str1" : "str2" (test)? "str1" : "str2" NO es un constante * porque el resultado de dicha expresión se encuentra solo en tiempo de ejecución y, por lo tanto, es indeterminado en tiempo de compilación, un hecho que causa que el compilador se queje. Por otro lado, esto funciona perfectamente bien printf("hi %s", test? "yes":"no")


Porque C no tiene tipo de string . Los literales de cadena se compilan en matrices de caracteres, a los que hace referencia un puntero char* .

C permite que se combinen literales adyacentes en tiempo de compilación , como en su primer ejemplo. El compilador de C tiene algunos conocimientos sobre cadenas. Pero esta información no está presente en tiempo de ejecución y , por lo tanto, la concatenación no puede suceder.

Durante el proceso de compilación, su primer ejemplo se "traduce" a:

int main() { static const char char_ptr_1[] = {''H'', ''i'', ''B'', ''y'', ''e'', ''/0''}; printf(char_ptr_1); }

Observe cómo el compilador combina las dos cadenas en una única matriz estática antes de que el programa se ejecute.

Sin embargo, su segundo ejemplo se "traduce" a algo como esto:

int main() { static const char char_ptr_1[] = {''H'', ''i'', ''/0''}; static const char char_ptr_2[] = {''B'', ''y'', ''e'', ''/0''}; static const char char_ptr_3[] = {''G'', ''o'', ''o'', ''d'', ''b'', ''y'', ''e'', ''/0''}; int test = 0; printf(char_ptr_1 (test ? char_ptr_2 : char_ptr_3)); }

Debe quedar claro por qué esto no se compila. El operador ternario ? se evalúa en tiempo de ejecución, no en tiempo de compilación, cuando las "cadenas" ya no existen como tales, sino solo como matrices de caracteres simples, referenciadas por punteros char* . A diferencia de los literales de cadena adyacentes, los punteros de caracteres adyacentes son simplemente un error de sintaxis.


Según el estándar C11, capítulo §5.1.1.2, concatenación de literales de cadena adyacentes:

Los tokens literales de cadena adyacentes se concatenan.

sucede en la fase de traducción . Por otra parte:

printf("Hi" (test ? "Bye" : "Goodbye"));

involucra al operador condicional, que se evalúa en tiempo de ejecución . Entonces, en tiempo de compilación, durante la fase de traducción, no hay literales de cadena adyacentes presentes, por lo tanto, la concatenación no es posible. La sintaxis no es válida y, por lo tanto, su compilador la informa.

Para elaborar un poco sobre la parte del por qué , durante la fase de preprocesamiento, los literales de cadena adyacentes se concatenan y se representan como un literal de cadena único (token). El almacenamiento se asigna en consecuencia y el literal de cadena concatenado se considera como una entidad única (un literal de cadena).

Por otro lado, en caso de concatenación en tiempo de ejecución, el destino debe tener suficiente memoria para contener la cadena concatenada literal , de lo contrario, no habrá forma de acceder a la salida concatenada esperada . Ahora, en el caso de los literales de cadena , ya se les ha asignado memoria en tiempo de compilación y no se pueden extender para que quepan en ninguna entrada entrante o se agreguen al contenido original. En otras palabras, no habrá forma de que se pueda acceder (presentar) al resultado concatenado como un literal de cadena único. Entonces, esta construcción es inherentemente incorrecta.

Solo para su información, para la concatenación de cadenas en tiempo de ejecución ( no literales ), tenemos la función de biblioteca strcat() que concatena dos cadenas . Aviso, la descripción menciona:

char *strcat(char * restrict s1,const char * restrict s2);

La función strcat() agrega una copia de la cadena a la que apunta s2 (incluido el carácter nulo de terminación) al final de la cadena a la que apunta s1 . El carácter inicial de s2 sobrescribe el carácter nulo al final de s1 . [...]

Entonces, podemos ver, el s1 es una cadena , no un literal de cadena . Sin embargo, como el contenido de s2 no se modifica de ninguna manera, puede ser un literal de cadena .


Si realmente desea que ambas ramas produzcan constantes de cadena en tiempo de compilación para elegir en tiempo de ejecución, necesitará una macro.

#include <stdio.h> #define ccat(s, t, a, b) ((t)?(s a):(s b)) int main ( int argc, char **argv){ printf("%s/n", ccat("hello ", argc > 2 , "y''all", "you")); return 0; }