¿Es una mala práctica usar un compilador de C ++ solo para la sobrecarga de funciones?

60

Así que estoy trabajando en un diseño de software usando C para un procesador determinado. El kit de herramientas incluye la capacidad de compilar C y C ++. Por lo que estoy haciendo, no hay asignación de memoria dinámica disponible en este entorno y el programa en general es bastante simple. Sin mencionar que el dispositivo casi no tiene potencia de procesador o recursos. Realmente no hay una gran necesidad de usar ningún C ++.

Dicho esto, hay algunos lugares donde realizo sobrecargas de funciones (una característica de C ++). Necesito enviar algunos tipos diferentes de datos y no tengo ganas de usar el printfformato de estilo con algún tipo de %sargumento (o lo que sea). He visto a algunas personas que no tenían acceso a un compilador de C ++ haciendo la printfcosa, pero en mi caso el soporte de C ++ está disponible.

Ahora estoy seguro de que podría tener la pregunta de por qué necesito sobrecargar una función para empezar. Así que intentaré responder eso ahora. Necesito transmitir diferentes tipos de datos a un puerto serie, así que tengo algunas sobrecargas que transmiten los siguientes tipos de datos:

unsigned char*
const char*
unsigned char
const char

Prefiero no tener un método que maneje todas estas cosas. Cuando llamo a la función, solo quiero que transmita el puerto serie, no tengo muchos recursos, así que no quiero hacer nada más que mi transmisión.

Alguien más vio mi programa y me preguntó, "¿por qué estás usando archivos CPP?" Entonces, esa es mi única razón. ¿Esa es una mala práctica?

Actualizar

Me gustaría abordar algunas preguntas:

Una respuesta objetiva a su dilema dependerá de:

  1. Si el tamaño del ejecutable crece significativamente si usa C ++.

En este momento, el tamaño del ejecutable consume el 4.0% de la memoria del programa (de 5248 bytes) y el 8.3% de la memoria de datos (de 342 bytes). Es decir, compilar para C ++ ... No sé cómo sería para C porque no he estado usando el compilador de C. Sé que este programa no crecerá más, así que por lo limitados que son los recursos, diría que estoy bien allí ...

  1. Si hay algún impacto negativo notable en el rendimiento si usa C ++.

Bueno, si lo hay, no me he dado cuenta de nada ... pero, de nuevo, esa podría ser la razón por la que hago esta pregunta, ya que no entiendo completamente.

  1. Si el código se puede reutilizar en una plataforma diferente donde solo está disponible un compilador de C.

Sé que la respuesta a esto es definitivamente no . De hecho, estamos considerando cambiarnos a un procesador diferente, pero solo a procesadores basados ​​en ARM más potentes (todo lo cual sé con certeza que tienen cadenas de herramientas de compilación C ++).

Fisgonear
fuente
59
Se sabe que uso C ++ para un proyecto solo con características de C solo para poder tener //comentarios. Si funciona, ¿por qué no?
Jules
76
La mala práctica sería restringirse a C cuando tiene un buen uso de las funciones que no proporciona.
Jerry Coffin
35
Cuando dices "usa un compilador de C ++" te refieres a "usa C ++". Sólo dilo. No puede compilar C con un compilador de C ++, pero puede cambiar de C a C ++ fácilmente, que es lo que realmente estaría haciendo.
user253751
44
"Por lo que estoy haciendo, no hay una asignación dinámica de memoria en el procesador y el programa es bastante simple en general. Sin mencionar que el dispositivo casi no tiene potencia ni recursos de procesador. Realmente no hay una gran necesidad de usar ningún C ++". Espero que la primera de esas dos oraciones se suponga que sean razones para no usar C ++, porque son bastante malas si lo son. C ++ está perfectamente bien para usar con sistemas integrados.
Pharap
21
@Jules Estoy seguro de que sabes esto y lo pensé hace un tiempo, pero en caso de que alguien que lea esto no lo haga: los //comentarios han estado en el estándar C desde C99.
Davislor

Respuestas:

77

No iría tan lejos como para llamarlo "mala práctica" per se , pero tampoco estoy convencido de que realmente sea la solución correcta a su problema. Si todo lo que quiere son cuatro funciones separadas para hacer sus cuatro tipos de datos, ¿por qué no hacer lo que los programadores de C han hecho desde tiempos inmemoriales?

void transmit_uchar_buffer(unsigned char *buffer);
void transmit_char_buffer(char *buffer);
void transmit_uchar(unsigned char c);
void transmit_char(char c);

Eso es efectivamente lo que el compilador de C ++ está haciendo entre bastidores de todos modos y no es una gran carga para el programador. Evita todos los problemas de "por qué estás escribiendo no completamente C con un compilador de C ++", y significa que nadie más en tu proyecto se va a confundir por qué bits de C ++ están "permitidos" y cuáles no.

Philip Kendall
fuente
8
Yo diría por qué no es porque el tipo que se transmite es (probablemente) un detalle de implementación, por lo que ocultarlo y dejar que el compilador se encargue de seleccionar la implementación puede resultar en un código más legible. Y si el uso de una función C ++ mejora la legibilidad, ¿por qué no hacer eso?
Jules
29
Incluso se puede #definetransmitir () usando C11_Generic
Deduplicator
16
@Jules Porque es muy confuso en cuanto a qué características de C ++ se pueden usar en el proyecto. ¿Se rechazaría un posible cambio que contenga objetos? ¿Qué pasa con las plantillas? ¿Comentarios de estilo C ++? Claro, puede solucionarlo con un documento de estilo de codificación, pero si todo lo que está haciendo es un simple caso de sobrecarga de funciones, simplemente escriba C en su lugar.
Philip Kendall el
25
@Phillip Los "comentarios de estilo C ++" han sido válidos en C durante más de una década.
David Conrad
12
@Jules: si bien el tipo que se transmite es probablemente un detalle de implementación para el software que hace cotizaciones de seguros, la aplicación OP parece ser un sistema integrado que realiza comunicación en serie, donde el tipo y el tamaño de los datos son de gran importancia.
whatsisname
55

Usar solo algunas características de C ++ y tratarlo como C no es exactamente común, pero tampoco es desconocido. De hecho, algunas personas incluso no usan ninguna función de C ++, excepto la verificación de tipos más estricta y poderosa. Simplemente escriben C (teniendo cuidado de escribir solo en la intersección común de C ++ y C), luego compilan con un compilador de C ++ para la verificación de tipos y un compilador de C para la generación de código (o simplemente se quedan con un compilador de C ++).

Linux es un ejemplo de una base de código, donde la gente se pregunta regularmente que los identificadores como classse renombran a klass, o kclass, de modo que puedan compilar Linux con un compilador de C ++. Obviamente, dada la opinión de Linus sobre C ++ , siempre son derribados :-D GCC es un ejemplo de una base de código que primero se transformó en "C ++ - clean C", y luego se refactorizó gradualmente para usar más funciones de C ++.

No hay nada malo con lo que estás haciendo. Si está realmente paranoico acerca de la calidad de generación de código de su compilador de C ++, puede usar un compilador como Comeau C ++, que compila a C como lenguaje de destino, y luego usa el compilador de C. De esa manera, también puede hacer inspecciones puntuales del código para ver si el uso de C ++ inyecta algún código imprevisto sensible al rendimiento. Sin embargo, ese no debería ser el caso para la sobrecarga, que literalmente genera automáticamente funciones con nombres diferentes: IOW, exactamente lo que harías en C de todos modos.

Jörg W Mittag
fuente
15

Una respuesta objetiva a su dilema dependerá de:

  1. Si el tamaño del ejecutable crece significativamente si usa C ++.
  2. Si hay algún impacto negativo notable en el rendimiento si usa C ++.
  3. Si el código se puede reutilizar en una plataforma diferente donde solo está disponible un compilador de C.

Si las respuestas a alguna de las preguntas son "sí", es mejor que cree funciones con nombres diferentes para diferentes tipos de datos y se quede con C.

Si las respuestas a todas las preguntas son "no", no veo ninguna razón por la que no deba usar C ++.

R Sahu
fuente
99
Debo decir que nunca he encontrado un compilador de C ++ que genere un código significativamente peor que un compilador de C para el código escrito en el subconjunto compartido de los dos lenguajes. Los compiladores de C ++ obtienen una mala reputación tanto para el tamaño como para el rendimiento, pero mi experiencia es que siempre es el uso inapropiado de las características de C ++ lo que causó el problema ... En particular, si le preocupa el tamaño, no use iostreams y no use plantillas, pero de lo contrario deberías estar bien.
Jules
@Jules: Solo por lo que vale (no mucho, IMO), he visto lo que se vendió como un compilador único para C y C ++ (Turbo C ++ 1.0, si la memoria sirve) produce resultados significativamente diferentes para una entrada idéntica. Sin embargo, según tengo entendido, esto fue antes de que terminaran su propio compilador de C ++, por lo que, aunque parecía un compilador en el exterior, realmente tenía dos compiladores completamente separados, uno para C y el otro para C ++.
Jerry Coffin
1
@JerryCoffin Si la memoria funciona, los productos Turbo nunca han tenido una gran reputación. Y si fuera una versión 1.0, podría ser excusado por no ser altamente refinado. Por lo tanto, probablemente no sea muy representativo.
Barmar
10
@Barmar: En realidad, tuvieron una reputación bastante decente durante bastante tiempo. Su mala reputación ahora se debe principalmente a su edad. Son competitivos con otros compiladores de la misma cosecha, pero nadie publica preguntas sobre cómo hacer las cosas con gcc 1.4 (o lo que sea). Pero tienes razón: no es muy representativo.
Jerry Coffin
1
@Jules Yo diría que incluso las plantillas están bien. A pesar de la teoría popular, la creación de instancias de una plantilla no aumenta implícitamente el tamaño del código, el tamaño del código generalmente no aumentará hasta que se utilice una función de una plantilla (en cuyo caso el aumento de tamaño será proporcional al tamaño de la función) o a menos que la plantilla sea declarando variables estáticas. Las reglas de la alineación aún se aplican, por lo que es posible escribir plantillas donde el compilador integra todas las funciones.
Pharap
13

Planteas la pregunta como si compilar con C ++ simplemente te diera acceso a más funciones. Este no es el caso. Compilar con un compilador de C ++ significa que su código fuente se interpreta como fuente de C ++, y C ++ es un lenguaje diferente de C. Los dos tienen un subconjunto común lo suficientemente grande como para programar de manera útil, pero cada uno tiene características que el otro carece, y es posible escribir código que sea aceptable en ambos idiomas pero interpretado de manera diferente.

Si realmente todo lo que desea es la sobrecarga de funciones, entonces realmente no veo el punto de confundir el problema al incorporar C ++. En lugar de diferentes funciones con el mismo nombre, distingue sus listas de parámetros, simplemente escriba funciones con diferentes nombres.

En cuanto a sus criterios objetivos,

  1. Si el tamaño del ejecutable crece significativamente si usa C ++.

El ejecutable puede ser ligeramente más grande cuando se compila como C ++, en relación con un código C similar creado como tal. Como mínimo, el ejecutable de C ++ tendrá el dudoso beneficio de la manipulación de nombres de C ++ para todos los nombres de funciones, en la medida en que los símbolos se conserven en el ejecutable. (Y de hecho, eso es lo que proporciona sus sobrecargas en primer lugar). Si la diferencia es lo suficientemente grande como para ser importante para usted es algo que tendría que determinar mediante un experimento.

  1. Si hay algún impacto negativo notable en el rendimiento si usa C ++.

Dudo que vea una diferencia de rendimiento notable para el código que describe frente a un hipotético análogo puro de C.

  1. Si el código se puede reutilizar en una plataforma diferente donde solo está disponible un compilador de C.

Yo arrojaría una luz ligeramente diferente sobre esto: si desea vincular el código que está creando con C ++ a otro código, entonces ese otro código también deberá escribirse en C ++ y construirse con C ++, o necesitará para hacer una provisión especial en su propio código (declarando el enlace "C"), que, además, no puede hacer para sus funciones sobrecargadas. Por otro lado, si su código está escrito en C y compilado como C, entonces otros pueden vincularlo con los módulos C y C ++. Este tipo de problema generalmente se puede superar cambiando las tornas, pero dado que realmente no parece necesitar C ++, ¿por qué aceptar ese problema en primer lugar?

John Bollinger
fuente
44
"El ejecutable puede ser un poco más grande cuando se compila como C ++ ... en la medida en que cualquier símbolo se conserve en el ejecutable". Sin embargo, para ser justos, cualquier cadena de herramientas de optimización decente debería tener una opción de enlazador para quitar estos símbolos en las compilaciones de "lanzamiento", lo que significa que solo aumentarían sus compilaciones de depuración. No creo que sea una gran pérdida. De hecho, con mayor frecuencia es un beneficio.
Cody Gray el
5

En el pasado, se promovió el uso de un compilador de C ++ como "una mejor C" como un caso de uso. De hecho, principios de C ++ fue exactamente eso. El principio de diseño subyacente era que solo podía usar las funciones que deseaba y no incurriría en el costo de las funciones que no estaba usando. Por lo tanto, podría sobrecargar las funciones (¡declarando la intención a través de la overloadpalabra clave!) Y el resto de su proyecto no solo se compilaría bien, sino que generaría un código no peor de lo que produciría el compilador de C.

Desde entonces, los idiomas han divergido un poco.

Todo mallocen su código C será un error de desajuste de tipo, ¡no es un problema en su caso sin memoria dinámica! Del mismo modo, todos sus voidpunteros en C lo harán tropezar, ya que tendrá que agregar lanzamientos explícitos. Pero ... ¿por qué lo haces de esa manera? ... te guiarán por el uso de las funciones de C ++ cada vez más.

Por lo tanto, podría ser posible con algo de trabajo extra. Pero servirá como una puerta de entrada a la adopción de C ++ a mayor escala. En unos años, la gente se quejará de su código heredado que parece que fue escrito en 1989, ya que reemplazan sus mallocllamadas con new, extraen bloques de código de cuerpos de bucle para llamar a un algoritmo en su lugar y reprenden el polimorfismo falso inseguro que podría han sido triviales si se hubiera permitido al compilador hacerlo.

Por otro lado, sabes que sería lo mismo si lo hubieras escrito en C, así que ¿alguna vez es incorrecto escribir en C en lugar de C ++ dada su existencia? Si la respuesta es "no", tampoco puede estar equivocado el uso de funciones seleccionadas de C ++ .

JDługosz
fuente
2

Muchos lenguajes de programación tienen una o más culturas que se desarrollan a su alrededor y tienen ideas particulares sobre lo que se supone que es un lenguaje. Si bien debería ser posible, práctico y útil tener un lenguaje de bajo nivel adecuado para la programación de sistemas que aumente un dialecto de C adecuado para tal propósito con algunas características de C ++ que también serían adecuadas, las culturas que rodean los dos idiomas no tienen Particularmente favorecen tal fusión.

He leído sobre compiladores C integrados que incorporaron algunas características de C ++, incluida la capacidad de tener

foo.someFunction(a,b,c);

interpretado como, esencialmente

typeOfFoo_someFunction(foo, a, b, c);

así como la capacidad de sobrecargar funciones estáticas (los problemas de cambio de nombre solo surgen cuando se exportanlas funciones están sobrecargadas). No hay ninguna razón por la que los compiladores de C no puedan soportar tal funcionalidad sin imponer requisitos adicionales en el entorno de enlace y tiempo de ejecución, pero el rechazo reflexivo de muchos compiladores de C de casi todo desde C ++ con el fin de evitar las cargas ambientales les hace rechazar incluso características que no impondrían tal costo. Mientras tanto, la cultura de C ++ tiene poco interés en cualquier entorno que no sea compatible con todas las características de ese lenguaje. A menos que o hasta que la cultura de C cambie para aceptar tales características, o la cultura de C ++ cambie para alentar la implementación de subconjuntos livianos, el código "híbrido" puede sufrir muchas de las limitaciones de ambos lenguajes, al tiempo que está limitado en su capacidad para cosechar Los beneficios de operar en un superconjunto combinado.

Si una plataforma admite C y C ++, el código de biblioteca adicional requerido para admitir C ++ probablemente hará que el ejecutable sea algo más grande, aunque el efecto no será particularmente grande. La ejecución de "características C" dentro de C ++ probablemente no se verá particularmente afectada. Un problema mayor puede ser cómo los optimizadores C y C ++ manejan varios casos de esquina. El comportamiento de los tipos de datos en una C se define principalmente por el contenido de los bits almacenados en él, y C ++ tiene una categoría reconocida de estructuras (PODS - Estructuras de datos antiguas y simples) cuya semántica también se define principalmente por los bits almacenados. Sin embargo, los estándares C y C ++ a veces permiten un comportamiento contrario al que implican los bits almacenados, y las excepciones al comportamiento de "bits almacenados" difieren entre los dos lenguajes.

Super gato
fuente
1
Opinión interesante pero no aborda la pregunta del OP.
R Sahu
@RSahu: el código que se ajusta a la "cultura" que rodea a un lenguaje es más compatible y más fácilmente adaptable a una variedad de implementaciones que el código que no lo hace. Las culturas de C y C ++ son contrarias al tipo de uso que sugiere el OP, agregaré algunos puntos más específicos con respecto a las preguntas específicas.
supercat
1
Tenga en cuenta que hay un grupo integrado / financiero / de juego en el comité estándar de C ++ que tiene como objetivo resolver exactamente el tipo de situaciones de "poco interés" que usted afirma que se descartan.
Yakk
@Yakk: Confieso que no he estado siguiendo el mundo de C ++ terriblemente de cerca, ya que mis intereses están principalmente en C; Sé que ha habido esfuerzos hacia dialectos más incrustados, pero no pensé que realmente hubieran llegado a ninguna parte.
supercat
2

Otro factor importante a considerar: quien herede su código.

¿Esa persona siempre será un programador de C con un compilador de C? Supongo que sí.

¿Esa persona también será un programador de C ++ con un compilador de C ++? Me gustaría estar razonablemente seguro de esto antes de hacer que mi código dependa de cosas específicas de C ++.

reinierpost
fuente
2

El polimorfismo es una característica realmente buena que C ++ proporciona de forma gratuita. Sin embargo, hay otros aspectos que debe tener en cuenta al elegir un compilador. Hay una alternativa para el polimorfismo en C, pero su uso puede causar algunas cejas levantadas. Es la función variadic, consulte el tutorial de la función Variadic .

En tu caso sería algo como

enum serialDataTypes
{
 INT =0,
 INT_P =1,
 ....
 }Arg_type_t;
....
....
void transmit(Arg_type_t serial_data_type, ...)
{
  va_list args;
  va_start(args, serial_data_type);

  switch(serial_data_type)
  {
    case INT: 
    //Send integer
    break;

    case INT_P:
    //Send data at integer pointer
    break;
    ...
   }
 va_end(args);
}

Me gusta el enfoque de Phillips, pero llena su biblioteca con muchas llamadas. Con lo anterior, la interfaz está limpia. Tiene sus inconvenientes y, en última instancia, es una cuestión de elección.

nikhil_kotian
fuente
Las funciones variables sirven principalmente para el caso de uso donde tanto el número de argumentos como sus tipos son variables. De lo contrario, no lo necesita, y en particular, es excesivo para su ejemplo particular. Sería más simple usar una función ordinaria que acepte un Arg_type_ty un void *apunte a los datos. Dicho esto, sí, dar a la función (única) un argumento que indique que el tipo de datos es una alternativa viable.
John Bollinger
1

Para su caso particular de sobrecarga estática de una "función" para algunos tipos diferentes, puede considerar usar C11 con su maquinaria de _Genericmacro . Siento que podría ser suficiente para sus necesidades limitadas.

Usando la respuesta de Philip Kendall, podría definir:

#define transmit(X) _Generic((X),      \
   unsigned char*: transmit_uchar_buffer, \
   char*: transmit_char_buffer,           \
   unsigned char: transmit_uchar,         \
   char: transmit_char) ((X))

y codifique transmit(foo) cualquiera que sea el tipo de foo(entre los cuatro tipos enumerados anteriormente).

Si solo le interesan los compiladores GCC (y compatibles, por ejemplo, Clang ), podría considerar __builtin_types_compatible_psu typeofextensión.

Basile Starynkevitch
fuente
1

¿Es una mala práctica usar un compilador de C ++ solo para la sobrecarga de funciones?

En mi humilde opinión, sí, y tendré que volverme esquizofrénico para responder a esto ya que amo ambos idiomas, pero no tiene nada que ver con la eficiencia, sino más bien con la seguridad y el uso idiomático de los idiomas.

Lado C

Desde el punto de vista de C, considero que es un desperdicio hacer que su código requiera C ++ solo para usar la sobrecarga de funciones. A menos que lo esté utilizando para el polimorfismo estático con plantillas de C ++, es un azúcar sintáctico tan trivial obtenido a cambio de cambiar a un lenguaje completamente diferente. Además, si alguna vez desea exportar sus funciones a un dylib (puede o no ser una preocupación práctica), ya no puede hacerlo de manera muy práctica para un consumo generalizado con todos los símbolos de nombre mutilado.

Lado C ++

Desde el punto de vista de C ++, no debería usar C ++ como C con sobrecarga de funciones. Este no es un dogmatismo estilístico, sino uno relacionado con el uso práctico de C ++ cotidiano.

Su tipo normal de código C es razonablemente sensato y "seguro" para escribir si está trabajando en contra del sistema de tipo C que prohíbe cosas como los copiadores structs. Una vez que esté trabajando en el sistema de tipos mucho más rico de C ++, las funciones diarias que son de gran valor como memsety memcpyno se convierten en funciones en las que debe apoyarse todo el tiempo. En cambio, son funciones que generalmente desea evitar como la peste, ya que con los tipos C ++, no debería tratarlos como bits y bytes sin procesar para copiar, barajar y liberar. Incluso si su código solo usa cosas como memsetprimitivas y UDT de POD en este momento, en el momento en que alguien agrega un ctor a cualquier UDT que usa (incluso solo agrega un miembro que requiere uno, comostd::unique_ptrmiembro) contra tales funciones o una función virtual o algo por el estilo, hace que toda su codificación normal de estilo C sea susceptible a un comportamiento indefinido. Tómelo del propio Herb Sutter:

memcpyy memcmpviolar el sistema de tipos. Usar memcpypara copiar objetos es como ganar dinero usando una fotocopiadora. Usar memcmppara comparar objetos es como comparar leopardos contando sus manchas. Puede parecer que las herramientas y los métodos hacen el trabajo, pero son demasiado groseros para hacerlo aceptablemente. Los objetos de C ++ tienen que ver con la ocultación de información (posiblemente el principio más rentable en ingeniería de software; consulte el Elemento 11): los objetos ocultan datos (consulte el Elemento 41) e idean abstracciones precisas para copiar esos datos a través de constructores y operadores de asignación (consulte los Elementos 52 a 55) . Arrasar todo eso memcpyes una violación grave de la ocultación de información, y a menudo conduce a fugas de memoria y recursos (en el mejor de los casos), bloqueos (peor) o comportamiento indefinido (peor) - Estándares de codificación C ++.

Muchos desarrolladores de C no estarían de acuerdo con esto y con razón, ya que la filosofía solo se aplica si está escribiendo código en C ++. Lo más probable está escribiendo código muy problemático si se utilizan funciones como memcpytodos los tiempos en el código que construye como C ++ , pero es perfectamente bien si lo hace en C . Los dos idiomas son muy diferentes a este respecto debido a las diferencias en el sistema de tipos. Es muy tentador observar el subconjunto de características que estos dos tienen en común y creer que uno puede usarse como el otro, especialmente en el lado de C ++, pero el código C + (o código C--) es generalmente mucho más problemático que C y C Código C ++.

Del mismo modo, no debería usar, digamos, mallocen un contexto de estilo C (lo que implica que no hay EH) si puede llamar a cualquier función C ++ directamente que pueda lanzar, ya que tiene un punto de salida implícito en su función como resultado de excepción que no puede atrapar efectivamente escribiendo código de estilo C, antes de poder acceder a freeesa memoria. Así que cuando usted tiene un archivo que se acumula como C ++ con una .cppextensión o lo que sea y lo hace todo este tipo de cosas como malloc, memcpy, memset,qsort, etc., entonces está pidiendo problemas más adelante si no es así, a menos que sea el detalle de implementación de una clase que solo funciona con tipos primitivos, momento en el que todavía necesita hacer un manejo de excepciones para estar seguro de excepciones. Si estás escribiendo código C ++ por el contrario quiere generalmente se basan en RAII y usar cosas como vector, unique_ptr, shared_ptr, etc, y evitar todos normales de codificación de estilo C, cuando sea posible.

La razón por la que puede jugar con cuchillas de afeitar en los tipos de datos de rayos X y C y jugar con sus bits y bytes sin ser propenso a causar daños colaterales en un equipo (aunque todavía puede lastimarse de cualquier manera) no es por lo que C los tipos pueden hacer, pero debido a lo que nunca podrán hacer. En el momento en que extienda el sistema de tipos de C para incluir características de C ++ como ctors, dtors y vtables, junto con el manejo de excepciones, todo el código idiomático de C se volverá mucho, mucho más peligroso de lo que es actualmente, y verá un nuevo tipo de evolución de la filosofía y la mentalidad que fomentará un estilo de codificación completamente diferente, como puede ver en C ++, que ahora considera incluso usar una mala práctica de puntero en bruto para una clase que gestiona la memoria en lugar de, por ejemplo, un recurso conforme a RAII como unique_ptr. Esa mentalidad no evolucionó a partir de una sensación absoluta de seguridad. Evolucionó a partir de lo que C ++ necesita específicamente para protegerse contra características como el manejo de excepciones dado lo que simplemente permite a través de su sistema de tipos.

Excepción-Seguridad

Nuevamente, en el momento en que esté en C ++ land, la gente esperará que su código sea seguro para las excepciones. Las personas pueden mantener su código en el futuro, dado que ya está escrito y compilado en C ++, y simplemente usar std::vector, dynamic_cast, unique_ptr, shared_ptr, etc., en código llamado directa o indirectamente por su código, creyendo que es inocuo ya que su código ya es "supuestamente" C ++ código. En ese punto, tenemos que enfrentar la posibilidad de que las cosas salgan mal, y luego, cuando tomas un código C perfecto y encantador como este:

int some_func(int n, ...)
{
    int* x = calloc(n, sizeof(int));
    if (x)
    {
        f(n, x); // some function which, now being a C++ function, may 
                 // throw today or in the future.
        ...
        free(x);
        return success;
    }
    return fail;
}

... ahora está roto. Necesita ser reescrito para ser seguro para excepciones:

int some_func(int n, ...)
{
    int* x = calloc(n, sizeof(int));
    if (x)
    {
        try
        {
            f(n, x); // some function which, now being a C++ function, may 
                     // throw today or in the future (maybe someone used
                     // std::vector inside of it).
        }
        catch (...)
        {
            free(x);
            throw;
        }
        ...
        free(x);
        return success;
    }
    return fail;
}

¡Bruto! Es por eso que la mayoría de los desarrolladores de C ++ exigirían esto en su lugar:

void some_func(int n, ...)
{
    vector<int> x(n);
    f(x); // some function which, now being a C++ function, may throw today
          // or in the future.
}

Lo anterior es un código seguro de excepción conforme a RAII del tipo que los desarrolladores de C ++ generalmente aprobarían, ya que la función no perderá ninguna línea de código que desencadene una salida implícita como resultado de a throw.

Elige un idioma

Debe adoptar el sistema de tipos y la filosofía de C ++ con RAII, excepción de seguridad, plantillas, OOP, etc., o adoptar C, que gira en gran medida en torno a bits y bytes sin formato. No debe formar un matrimonio impío entre estos dos idiomas, y en su lugar separarlos en idiomas distintos para que sean tratados de manera muy diferente en lugar de difuminarlos.

Estos idiomas quieren casarse contigo. Por lo general, debes elegir uno en lugar de salir y perder el tiempo con ambos. O puedes ser un polígamo como yo y casarte con ambos, pero debes cambiar completamente tu forma de pensar cuando pasas tiempo uno con el otro y mantenerlos bien separados entre sí para que no peleen entre ellos.

Tamaño binario

Solo por curiosidad, traté de tomar mi implementación de lista gratuita y punto de referencia en este momento y portarlo a C ++ ya que tenía mucha curiosidad sobre esto:

[...] no sé cómo sería para C porque no he estado usando el compilador de C.

... y quería saber si el tamaño binario se inflaría simplemente construyéndose como C ++. Me obligó a esparcir lanzamientos explícitos por todo el lugar, lo cual era fugitivo (una razón por la que me gusta escribir cosas de bajo nivel como asignadores y estructuras de datos en C mejor) pero solo me llevó un minuto.

Esto era solo comparar una compilación de lanzamiento MSVC de 64 bits para una aplicación de consola simple y con un código que no usaba ninguna función de C ++, ni siquiera la sobrecarga del operador, solo la diferencia entre construirlo con C y usar, por ejemplo, en <cstdlib>lugar de <stdlib.h>y cosas así, pero me sorprendió descubrir que no hizo ninguna diferencia en el tamaño binario.

El binario era 9,728bytes cuando se construyó en C, y también 9,278bytes cuando se compiló como código C ++. En realidad no esperaba eso. Pensé que cosas como EH al menos agregarían un poco allí (pensé que al menos serían como cien bytes diferentes), aunque probablemente fue capaz de darse cuenta de que no había necesidad de agregar instrucciones relacionadas con EH ya que solo estoy usando la biblioteca estándar C y nada arroja. Pensé algoagregaría un poco al tamaño binario de cualquier manera, como RTTI. De todos modos, fue genial ver eso. Por supuesto, no creo que debas generalizar a partir de este resultado, pero al menos me impresionó un poco. Tampoco tuvo ningún impacto en los puntos de referencia, y naturalmente, ya que me imagino que el tamaño binario resultante idéntico también significó instrucciones de máquina idénticas.

Dicho esto, ¿a quién le importa el tamaño binario con los problemas de seguridad e ingeniería mencionados anteriormente? Así que de nuevo, elige un idioma y adopta su filosofía en lugar de tratar de bastardarlo; Eso es lo que recomiendo.


fuente