simbolo - para que sirven los corchetes en matematicas
falla de segmentación cuando se usan corchetes dobles con printf (3)
#include<stdio.h>
#define POOLNAME_FMT "Hello"
void main() {
printf((POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory",5));
}
¿Por qué da error de segmentación cuando uso corchetes dobles con printf
? es decir, printf(( ));
?
Está utilizando el operador de coma sin darse cuenta:
( ... "in pool not enough memory",5)
^
dado que el operador de coma evaluará su operando izquierdo y descartará el resultado, y luego evaluará y devolverá el operando correcto, usted terminará con:
printf( 5 ) ;
que intentará convertir un int
a un const char *restrict
para la cadena de formato, que seguramente no apuntará a la memoria válida. Sin el ()
, el ,
habría sido un separador para los argumentos de la función.
The ()
es una expresión en este contexto; si miramos el borrador del estándar C99 sección 6.5.1
Expresiones primarias , tenemos:
( expression )
por lo tanto ,
el ,
se trata como un operador, mientras que podemos ver desde la sección 6.5.2
operadores de Postfix :
postfix-expression ( argument-expression-listopt )
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression
^
El ,
es solo un separador en una llamada de función.
Tener las advertencias habilitadas debería haber ayudado aquí, gcc
me da algunas advertencias para este programa:
advertencia: el operando de la izquierda de la expresión de coma no tiene efecto [-Wunused-value]
y
advertencia: pasar el argumento 1 de ''printf'' hace puntero desde entero sin un molde [habilitado por defecto] nota: esperado ''const char * restring'' pero el argumento es de tipo ''int''
Esto se debe a que printf es una función que aceptará sus argumentos en paréntesis únicos, y el segundo conjunto de paréntesis está realmente abriendo una subexpresión:
(string "string" string "string" , 5)
Las primeras cuatro cadenas se concatenan en tiempo de compilación, produciendo:
("string", 5)
Esto luego se evalúa:
-
"string"
evalúa como un puntero al primer carácter de la misma - a
,
b evalúa primero, luego arroja el resultado, luego evalúa y devuelve b -
5
evalúa a una constante entera 5
Entonces, en efecto, estás llamando:
printf(5);
(Esto es porque la cadena no tiene efectos secundarios).
Algo como esto, sin embargo, funcionaría:
printf((POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory"),5);
Observe cómo se movieron la coma y los cinco fuera de la subexpresión entre paréntesis.
Porque (a, b)
es en realidad un solo valor. Calcula b
y devuelve el valor de b
.
Entonces, lo que estás haciendo es básicamente:
/* calculate before `,` and ignore */
POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory";
/* call printf with after `,` */
printf(5);
Lo cual está claramente mal.
Cuando escribe func(a, b)
como una llamada a función, C sabe enviar a
y b
como argumentos separados a func
. Cuando dice func((a, b))
, está diciendo explícitamente que (a, b)
es un valor y que el resultado (es decir, el valor de b
) se debe enviar a func
como un único argumento.
Si compila con advertencias, y si su compilador es amable con usted, podría advertirle sobre esto. Si su compilador no es bueno, todavía debe quejarse de que está dando un int
donde se espera un const char *
.
Si usa gcc
, recomiendo compilar con -Wall
, always.