Guiones bajos en C++: reglas no obvias que rompen el código

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Guiones bajos en C++: asesinos silenciosos de tu código

\n\n

Imagina la situación: escribes código C++ limpio y hermoso. El compilador calla, el linter no se queja, todo funciona perfectamente. Y luego, ¡pum! — y en otro compilador o con una nueva versión del estándar, todo se rompe sin razón aparente. ¿Te suena familiar?

\n\n

La mayoría de las veces, la raíz del mal se encuentra en los símbolos de guion bajo (_), aparentemente inofensivos. Este tema es un verdadero "cementerio" para principiantes e incluso desarrolladores experimentados de C++. No en vano, la pregunta en Stack Overflow sobre las reglas de uso de guiones bajos ha acumulado decenas de miles de visitas. Aclaremos de una vez por todas qué se puede, qué no se puede y cómo no caer en la trampa del comportamiento indefinido (UB).

\n\n

¿Por qué el estándar C++ es tan estricto con los guiones bajos?

\n\n

La raíz del problema está en la compatibilidad y el espacio de nombres global. La biblioteca estándar de C++ utiliza activamente guiones bajos para sus necesidades internas. Si accidentalmente creas un identificador que entra en conflicto con los nombres internos de la biblioteca o del compilador, ¡todo está perdido! El compilador puede redefinir silenciosamente tu variable y obtendrás un comportamiento indefinido (Undefined Behavior) que se manifestará en el momento más inoportuno.

\n\n

El estándar C++ (desde C++03 y en todas las versiones posteriores, incluyendo C++20 y C++23) especifica claramente qué identificadores están reservados para la implementación. Violar estas reglas hace que tu código no solo sea incorrecto, sino no portátil.

\n\n

Top 5 errores mortales con guiones bajos

\n\n

Analicemos los errores más comunes en los que incluso los programadores experimentados tropiezan.

\n\n

Error n.º 1: Doble guion bajo en cualquier lugar

\n\n

Regla: Cualquier identificador que contenga dos caracteres de guion bajo consecutivos (__) en cualquier lugar está reservado para la implementación.

\n\n
// ¡MAL! Reservado para la "implementación"\nint __myVariable = 42;\nvoid my__function();\nclass My__Class {};\n\n// BIEN\nint myVariable = 42;\nvoid my_function();\nclass MyClass {};\n
\n\n

¿Por qué es peligroso? El compilador puede usar __myVariable para sus macros internas. Por ejemplo, muchos compiladores definen __LINE__ o __cplusplus. Si creas tu propio __LINE__, el compilador podría simplemente ignorar tu definición o, peor aún, reemplazarla con su propio valor. El resultado es UB.

\n\n

Error n.º 2: Guion bajo + letra mayúscula en el ámbito global

\n\n

Regla: Un identificador que comienza con un guion bajo seguido de una letra mayúscula (A-Z) está reservado para la implementación en cualquier ámbito.

\n\n
// ¡MAL! ¡Incluso en el ámbito local!\nvoid foo() {\n    int _MyVar = 10; // Infracción de la regla\n}\n\n// ¡MAL! Globalmente, aún más\nint _GlobalVar = 20;\n\n// BIEN\nvoid foo() {\n    int myVar = 10;\n}\n
\n\n

Esta regla es la más engañosa. Muchos piensan: "Bueno, estoy dentro de una función, ¿a quién le molesta esto?". ¡Sí molesta! El estándar no hace excepciones para el ámbito local si el identificador comienza con un guion bajo y una letra mayúscula. El compilador tiene todo el derecho de reservar esos nombres para sus propios fines.

\n\n

Error n.º 3: Guion bajo al inicio + letra minúscula en el ámbito global

\n\n

Regla: Un identificador que comienza con un guion bajo seguido de una letra minúscula (a-z) está reservado para la implementación en el ámbito global (namespace scope).

\n\n
// ¡MAL! En el espacio de nombres global\nint _myGlobal = 0;\nvoid _helperFunction();\n\n// BIEN — dentro de una función o clase\nclass MyClass {\n    int _memberVar; // Dentro de la clase — se puede (pero mejor m_)\n};\n\nvoid foo() {\n    int _localVar = 5; // Dentro de la función                

Blogs

Book Recommendations