¿Por qué ANSI C no tiene espacios de nombres?

93

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?

Pulkit Sinha
fuente
13
¡Utilice C ++ como C-con-espacio de nombres!
AraK
3
Por supuesto que puedo, pero aún me gustaría saber
Pulkit Sinha
5
2 cosas. Una sintaxis distintiva innecesaria: todos los demás lenguajes con espacios de nombres solo usan '.' como separador ya que no es ambiguo con otros usos de '.'. Y, lo que es más crítico, c ++ nunca introdujo una directiva using con ámbito. Lo que significaba que los programadores usaban en exceso las directivas para importar espacios de nombres al alcance global. Lo que significaba que el comité de estándares de c ++ ahora no puede agregar nuevas características a std :: ever ya que la cantidad de código que se rompería como resultado ha hecho que la partición sea redundante.
Chris Becke
2
@Chris Becke: Me gusta la sintaxis distintiva. Me gusta saber si estoy viendo una clase en un espacio de nombres o un miembro en una clase.
JeremyP
6
@ChrisBecke, esto tiene un retraso de algunos años, pero es interesante que argumente que los espacios de nombres de C ++ se implementaron de manera deficiente, por lo que no deberían implementarse en C. Luego, observe que otros lenguajes los implementan sin los problemas de C ++. Si otros lenguajes pueden hacerlo, ¿por qué no presentarles C?
weberc2

Respuestas:

68

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
8
En realidad, hay más de dos espacios de nombres. Además de los dos que menciona, hay un espacio de nombres para etiquetas y espacios de nombres para los miembros de cada estructura y unión.
JeremyP
@JeremyP: Muchas gracias por la corrección. Solo escribí esto de la memoria, no verifiqué el estándar :-)
2
¿qué pasa con el espacio de nombres para las funciones?
themihai
8
Esto bien puede llamarse espacios de nombres, pero creo que estos no son el tipo de espacios de nombres por los que el OP estaba preguntando.
avl_sweden
1
@jterm Nop. No estoy abogando por piratear las funciones de C, simplemente exponiendo los hechos. Cada structdefinició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 los structs no pueden tener miembros estáticos.
JeremyP
101

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.

invitado
fuente
12
... y los compiladores son lo suficientemente inteligentes como para "desreferenciar" el puntero de función en el momento de la compilación cuando lo hace library.method1()?
einpoklum
1
Esto es tan asombroso. Una cosa que podría agregar es que estoy intentando hacer que todas mis funciones en mis .carchivos sean estáticas de forma predeterminada, por lo que las únicas funciones expuestas son las expuestas explícitamente en la const structdefinición del .carchivo.
lastmjs
3
Es una gran idea, pero ¿cómo se manejan las constantes y enumeraciones?
nowox
1
@einpoklum: lo siento necro, pero al menos a partir de la versión 6.3.0, gcc calculará la dirección real de function1/ method2al compilar con ambos -O2y -flto. A menos que compile dichas bibliotecas junto con su propia fuente, este enfoque agregará algo de sobrecarga a sus llamadas a funciones.
Alex Reinking
3
@AlexReinking: Bueno, eso es bueno, pero nunca obtendríamos estas funciones en línea. Y necro'ing es genial, no es necesario disculparse.
Einpoklum
25

C tiene espacios de nombres. La sintaxis es namespace_name. Incluso puede anidarlos como en general_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.

R .. GitHub DEJA DE AYUDAR A ICE
fuente
24
Yo lo veo diferente. Complicar la gramática, introducir cambios de nombre en símbolos, etc. para lograr algo que ya era trivial de hacer con el preprocesador es lo que yo llamaría un truco sucio y un diseño deficiente.
R .. GitHub DEJA DE AYUDAR A ICE
41
No veo cómo puedes realmente apoyar esa posición. Pregunte a la comunidad de Javascript sobre la integración de proyectos cuando todos los demás sistemas tengan un truco propio diferente para implementar espacios de nombres. Nunca escuché a nadie quejarse de que la palabra clave 'espacio de nombres' o 'paquete' agregue demasiada complejidad a su lenguaje. Por otro lado, tratar de depurar código lleno de macros puede volverse complicado rápidamente.
weberc2
5
He escuchado a mucha gente quejarse de la manipulación de nombres de C ++ (desde el punto de vista de la depuración, la cadena de herramientas, la compatibilidad ABI, la búsqueda dinámica de símbolos, ...) y la complejidad de no saber a qué se refiere realmente un nombre en particular.
R .. GitHub DEJA DE AYUDAR A ICE
6
@R .. Eso no sucedería si la manipulación de nombres en C ++ estuviera estandarizada. Esto por sí solo no ayudaría con la compatibilidad ABI, pero definitivamente solucionaría el problema de asignación de nombres.
Malcolm
20
Me parece alucinante que la gente de C realmente discuta esto con seriedad. Hay muchas características en C ++ con bordes afilados que causan dolor a la gente. Los espacios de nombres no son una de esas características. Son geniales, funcionan muy bien. Y nada es trivial con el preprocesador, para que conste. Finalmente, exigir nombres es trivial, hay muchas utilidades de línea de comando que lo harán por usted.
Nir Friedman
12

Históricamente, los compiladores de C no modifican los nombres (lo hacen en Windows, pero la modificación de la cdeclconvenció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 ++.

Christoph
fuente
2
Pero, ¿por qué es eso un problema? Quiero decir, supongamos que todos los nombres con espacios de nombres comenzarían con _da13cd6447244ab9a30027d3d0a08903 y luego el nombre (¿Es un UUID v4 que acabo de generar)? Existe la posibilidad de que esto rompa los nombres que usan este UUID en particular, pero esa posibilidad es esencialmente cero. Por lo tanto, en la práctica no habrá problemas para manipular only_namespace_names .
einpoklum
7

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

ama
fuente
2
¿Hay algún movimiento en el comité de estándares para agregar espacios de nombres a C en el futuro? ¿Es posible que con el cambio al módulo C / C ++ esto lo haga más fácil en el futuro?
lanoxx
1
@lanoxx No hay voluntad de agregar espacios de nombres a C debido a razones de compatibilidad con versiones anteriores.
themihai
6

No es una respuesta, pero no un comentario. C no proporciona una forma de definir namespaceexplí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 usingpuede importar from mylib.

Khachik
fuente
Tampoco puede reemplazar las dos últimas líneas con lo namespace mylib { void init(); void say_hello(); }que también es importante (ish).
einpoklum
3

ANSI C se inventó antes que los espacios de nombres.

Crashworks
fuente
10
¿Era? La primera especificación ANSI C fue 1989. Estoy bastante seguro de que los espacios de nombres (de una forma u otra) estaban en lenguajes de programación antes de esa fecha. Ada, por ejemplo, se estandarizó en 1983 y tenía paquetes como espacios de nombres. Éstos, a su vez, se basaron esencialmente en módulos Modula-2.
SOLO MI OPINIÓN correcta
4
No fecharía la invención de ANSI C cuando su especificación fue adoptada oficialmente; el idioma existía de antemano, y la especificación simplemente documentaba lo que ya estaba allí. Aunque a partir de algunas de las respuestas en este sitio, uno podría pensar que la especificación fue primero y el primer compilador como una ocurrencia tardía.
Crashworks
ANSI C tenía algunas diferencias significativas con respecto a pre-ANSI C, pero los espacios de nombres no eran una de ellas.
dan04
Mientras tanto, lo estoy escribiendo en 2020, mucho después de que existieran los espacios de nombres. Los últimos estándares C todavía no los tienen. Por mucho que C tenga sentido, esta es una característica que falta mucho.
3

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.

einpoklum
fuente
1
Creo que veremos que el espacio de nombres en C es solo si estas personas se organizan y crean una extensión (es) con soporte de espacio de nombres. Entonces los organismos ISO no tendrán más remedio que traerlos a publicarlos como estándar (con más o menos cambios). Así es como lo hizo javascript (que tiene algunas similitudes con C a este respecto).
themihai
3
@themihai: "crear una extensión" = hacer que las personas gcc y clang compilen espacios de nombres.
einpoklum
1

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

_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);

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!

Andy Curtis
fuente
3
Sus enlaces explican cómo agregar espacios de nombres. Sin embargo, la pregunta era por qué no se admiten los espacios de nombres. Entonces, esta respuesta no es una respuesta y debería ser un comentario.
Thomas Weller