#include <iostream>
#include <cmath>
/* Intentionally incorrect abs() which seems to override std::abs() */
int abs(int a) {
return a > 0? -a : a;
}
int main() {
int a = abs(-5);
int b = std::abs(-5);
std::cout<< a << std::endl << b << std::endl;
return 0;
}
Esperaba que la salida fuera -5y 5, pero la salida es -5y -5.
Me pregunto por qué sucederá este caso.
¿Tiene algo que ver con el uso de stdo qué?

abses incorrecta.absefectos rotosstd::abs().5y5con clang,-5y-5con gcc.return 0; eso hubiera evitado que la gente pensara que implementó la función de manera incorrecta involuntariamente y habría aclarado el comportamiento deseado y real.Respuestas:
La especificación del lenguaje permite que las implementaciones se implementen
<cmath>declarando (y definiendo) las funciones estándar en el espacio de nombres global y luego llevándolas al espaciostdde nombres por medio de declaraciones de uso. No se especifica si se utiliza este enfoque.Aparentemente, se trata de una de las implementaciones que decidió seguir este enfoque (por ejemplo, GCC). Es decir, su implementación proporciona
::abs, mientras questd::abssimplemente "se refiere" a::abs.Una pregunta que permanece en este caso es por qué, además del estándar
::abs, pudo declarar el suyo::abs, es decir, por qué no hay error de definición múltiple. Esto podría deberse a otra característica proporcionada por algunas implementaciones (por ejemplo, GCC): declaran funciones estándar como los llamados símbolos débiles , lo que le permite "reemplazarlos" con sus propias definiciones.Estos dos factores juntos crean el efecto que observa: el reemplazo de símbolo débil de
::abstambién da como resultado el reemplazo destd::abs. Lo bien que esto concuerda con el estándar del lenguaje es una historia diferente ... En cualquier caso, no confíe en este comportamiento, no está garantizado por el lenguaje.En GCC, este comportamiento se puede reproducir con el siguiente ejemplo minimalista. Un archivo fuente
Otro archivo fuente
En este caso, también observará que la nueva definición de
::foo("Goodbye!") en el segundo archivo fuente también afecta el comportamiento deN::foo. Ambas llamadas saldrán"Goodbye!". Y si elimina la definición de::foodel segundo archivo fuente, ambas llamadas se enviarán a la definición::fooy salida "original""Hello!".El permiso otorgado por el 20.5.1.2/4 anterior está ahí para simplificar la implementación de
<cmath>. Se permite que las implementaciones incluyan simplemente el estilo C<math.h>, luego redeclaren las funcionesstdy agreguen algunas adiciones y ajustes específicos de C ++. Si la explicación anterior describe correctamente la mecánica interna del problema, entonces una gran parte depende de la posibilidad de reemplazar los símbolos débiles por las versiones de estilo C de las funciones.Tenga en cuenta que si simplemente reemplazamos globalmente
intcondoubleen el programa anterior, el código (en GCC) se comportará "como se esperaba": se generará-5 5. Esto sucede porque la biblioteca estándar de C no tieneabs(double)función. Al declarar nuestroabs(double), no reemplazamos nada.Pero si después de cambiar de
intcondoubletambién cambiamos deabsafabs, el comportamiento extraño original reaparecerá en todo su esplendor (salida-5 -5).Esto es consistente con la explicación anterior.
fuente
using ::abs;parecido para el, porusing ::asin;lo que puede anular la declaración, otro punto a mencionar es que las funciones de espacio de nombres definidas en std no se declaran para int sino para double , float#include<cmath>en mi código, obtuve la misma respuestaabsse puede declarar<cstdlib>, que podría incluirse implícitamente mediante<iostream>. Intente eliminar el suyoabsy ver si aún se compila.Su código provoca un comportamiento indefinido.
C ++ 17 [nombres.extern] / 4:
Por lo tanto, no puede crear una función con el mismo prototipo que la función de la biblioteca C estándar
int abs(int);. Independientemente de qué encabezados incluya realmente o si esos encabezados también colocan los nombres de las bibliotecas de C en el espacio de nombres global.Sin embargo, podría sobrecargarse
abssi proporciona diferentes tipos de parámetros.fuente