Tener espacios de nombres parece una obviedad para la mayoría de los idiomas. Pero por lo que puedo decir, ANSI C no lo admite. Por qué no? ¿Tiene planes de incluirlo en un futuro estándar?
c
namespaces
ansi-c
Pulkit Sinha
fuente
fuente
Respuestas:
C tiene espacios de nombres. Uno para etiquetas de estructura y otro para otros tipos. Considere la siguiente definición:
struct foo { int a; }; typedef struct bar { int a; } foo;
El primero tiene etiqueta foo, y el último se convierte en tipo foo con typedef. Todavía no ocurre ningún conflicto de nombres. Esto se debe a que las etiquetas y los tipos de estructura (tipos integrados y tipos definidos por tipo) viven en espacios de nombres separados.
Lo que C no permite es crear un nuevo espacio de nombres por voluntad. C se estandarizó antes de que esto se considerara importante en un idioma, y agregar espacios de nombres también amenazaría la compatibilidad con versiones anteriores, porque requiere alterar los nombres para que funcione correctamente. Creo que esto se puede atribuir a tecnicismos, no a filosofía.
EDITAR: JeremyP afortunadamente me corrigió y mencionó los espacios de nombres que me perdí. Hay espacios de nombres para etiquetas y también para miembros de estructura / unión.
fuente
struct
definición declara un nuevo espacio de nombres para sus miembros. No estoy abogando por explotar ese hecho, ni estoy al tanto de ningún medio de explotarlo, ya que losstruct
s no pueden tener miembros estáticos.Para completar, hay varias formas de lograr los "beneficios" que puede obtener de los espacios de nombres, en C.
Uno de mis métodos favoritos es usar una estructura para albergar un montón de punteros de método que son la interfaz de su biblioteca / etc.
Luego usa una instancia externa de esta estructura que inicializa dentro de su biblioteca apuntando a todas sus funciones. Esto le permite mantener sus nombres simples en su biblioteca sin pisar el espacio de nombres del cliente (que no sea la variable externa en el alcance global, 1 variable frente a posiblemente cientos de métodos ..)
Hay algo de mantenimiento adicional involucrado, pero creo que es mínimo.
Aquí hay un ejemplo:
/* interface.h */ struct library { const int some_value; void (*method1)(void); void (*method2)(int); /* ... */ }; extern const struct library Library; /* interface.h */ /* interface.c */ #include "interface.h" void method1(void) { ... } void method2(int arg) { ... } const struct library Library = { .method1 = method1, .method2 = method2, .some_value = 36 }; /* end interface.c */ /* client code */ #include "interface.h" int main(void) { Library.method1(); Library.method2(5); printf("%d\n", Library.some_value); return 0; } /* end */
El uso de . La sintaxis crea una fuerte asociación sobre el método clásico Library_function () Library_some_value. Sin embargo, existen algunas limitaciones, por ejemplo, no puede usar macros como funciones.
fuente
library.method1()
?.c
archivos sean estáticas de forma predeterminada, por lo que las únicas funciones expuestas son las expuestas explícitamente en laconst struct
definición del.c
archivo.function1
/method2
al compilar con ambos-O2
y-flto
. A menos que compile dichas bibliotecas junto con su propia fuente, este enfoque agregará algo de sobrecarga a sus llamadas a funciones.C tiene espacios de nombres. La sintaxis es
namespace_name
. Incluso puede anidarlos como engeneral_specific_name
. Y si desea poder acceder a los nombres sin escribir el nombre del espacio de nombres cada vez, incluya las macros del preprocesador relevantes en un archivo de encabezado, por ejemplo#define myfunction mylib_myfunction
Esto es mucho más limpio que la manipulación de nombres y las otras atrocidades que ciertos lenguajes cometen para entregar espacios de nombres.
fuente
Históricamente, los compiladores de C no modifican los nombres (lo hacen en Windows, pero la modificación de la
cdecl
convención de llamada consiste en solo agregar un prefijo de subrayado).Esto facilita el uso de bibliotecas C de otros lenguajes (incluido el ensamblador) y es una de las razones por las que a menudo ve
extern "C"
envoltorios para las API de C ++.fuente
solo razones históricas. nadie pensó en tener algo como un espacio de nombres en ese momento. También estaban tratando de mantener el lenguaje simple. Pueden tenerlo en el futuro
fuente
No es una respuesta, pero no un comentario. C no proporciona una forma de definir
namespace
explícitamente. Tiene alcance variable. Por ejemplo:int i=10; struct ex { int i; } void foo() { int i=0; } void bar() { int i=5; foo(); printf("my i=%d\n", i); } void foobar() { foo(); bar(); printf("my i=%d\n", i); }
Puede usar nombres calificados para variables y funciones:
mylib.h void mylib_init(); void mylib_sayhello();
La única diferencia con los espacios de nombres es que no se puede ni se
using
puede importarfrom mylib
.fuente
namespace mylib { void init(); void say_hello(); }
que también es importante (ish).ANSI C se inventó antes que los espacios de nombres.
fuente
Porque las personas que desean agregar esta capacidad a C no se han reunido y organizado para ejercer cierta presión sobre los equipos de autores de compiladores y los organismos ISO.
fuente
C no admite espacios de nombres como C ++. La implementación de los espacios de nombres de C ++ modifica los nombres. El enfoque que se describe a continuación le permite obtener el beneficio de los espacios de nombres en C ++ mientras tiene nombres que no están alterados. Me doy cuenta de que la naturaleza de la pregunta es por qué C no admite espacios de nombres (y una respuesta trivial sería que no lo hace porque no se implementó :)). Pensé que podría ayudar a alguien a ver cómo he implementado la funcionalidad de las plantillas y los espacios de nombres.
Escribí un tutorial sobre cómo aprovechar los espacios de nombres y / o las plantillas usando C.
Espacios de nombres y plantillas en C
Espacios de nombres y plantillas en C (usando listas vinculadas)
Para el espacio de nombres básico, simplemente se puede prefijar el nombre del espacio de nombres como una convención.
namespace MY_OBJECT { struct HANDLE; HANDLE *init(); void destroy(HANDLE * & h); void do_something(HANDLE *h, ... ); }
Se puede escribir como
struct MY_OBJECT_HANDLE; struct MY_OBJECT_HANDLE *my_object_init(); void my_object_destroy( MY_OBJECT_HANDLE * & h ); void my_object_do_something(MY_OBJECT_HANDLE *h, ... );
Un segundo enfoque que he necesitado que usa el concepto de espacio de nombres y plantillas es usar la concatenación de macros e incluir. Por ejemplo, puedo crear un
template<T> T multiply<T>( T x, T y ) { return x*y }
usando archivos de plantilla de la siguiente manera
multiplicar-plantilla.h
multiplicar-plantilla.c
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) { return x*y; }
Ahora podemos definir int_multiply de la siguiente manera. En este ejemplo, crearé un archivo int_multiply.h / .c.
int_multiply.h
#ifndef _INT_MULTIPLY_H #define _INT_MULTIPLY_H #ifdef _multiply_ #undef _multiply_ #endif #define _multiply_(NAME) int ## _ ## NAME #ifdef _multiply_type_ #undef _multiply_type_ #endif #define _multiply_type_ int #include "multiply-template.h" #endif
int_multiply.c
#include "int_multiply.h" #include "multiply-template.c"
Al final de todo esto, tendrá una función y un archivo de encabezado para.
int int_multiply( int x, int y ) { return x * y }
Creé un tutorial mucho más detallado sobre los enlaces proporcionados que muestran cómo funciona con listas enlazadas. ¡Ojalá esto ayude a alguien!
fuente