Veo algunas respuestas válidas aquí, pero voy a profundizar un poco más en los detalles.
Vaya al resumen a continuación para obtener la respuesta a su pregunta principal si no desea revisar todo este muro de texto.
Abstracción
Entonces, en este caso, ¿qué estoy pagando?
Estás pagando por la abstracción . Ser capaz de escribir código más simple y amigable para los humanos tiene un costo. En C ++, que es un lenguaje orientado a objetos, casi todo es un objeto. Cuando usas cualquier objeto, tres cosas principales siempre sucederán debajo del capó:
- Creación de objetos, básicamente asignación de memoria para el objeto en sí y sus datos.
- Inicialización de objetos (generalmente a través de algún
init()método). Por lo general, la asignación de memoria ocurre debajo del capó como lo primero en este paso.
- Destrucción de objetos (no siempre).
No lo ve en el código, pero cada vez que usa un objeto, las tres cosas anteriores deben suceder de alguna manera. Si hicieras todo manualmente, el código obviamente sería mucho más largo.
Ahora, la abstracción se puede hacer de manera eficiente sin agregar gastos generales: tanto los compiladores como los programadores pueden utilizar la inlínea de métodos y otras técnicas para eliminar los gastos generales de la abstracción, pero este no es su caso.
¿Qué está pasando realmente en C ++?
Aquí está, desglosado:
- La
std::ios_baseclase se inicializa, que es la clase base para todo lo relacionado con E / S.
- El
std::coutobjeto se inicializa.
- Su cadena se carga y se pasa a
std::__ostream_insert, que (como ya lo descubrió por el nombre) es un método de std::cout(básicamente el <<operador) que agrega una cadena a la secuencia.
cout::endltambién se pasa a std::__ostream_insert.
__std_dso_handlese pasa a __cxa_atexit, que es una función global que se encarga de "limpiar" antes de salir del programa. __std_dso_handleesta función llama a sí misma para desasignar y destruir los objetos globales restantes.
Entonces, ¿usar C == sin pagar nada?
En el código C, están ocurriendo muy pocos pasos:
- Su cadena se carga y se pasa a
putstravés del ediregistro.
puts se llama.
No hay objetos en ningún lado, por lo tanto, no es necesario inicializar / destruir nada.
Sin embargo, esto no quiere decir que usted no está "pagando" por nada en C . Todavía está pagando por la abstracción, y también por la inicialización de la biblioteca estándar de C y la resolución dinámica de la printffunción (o, en realidadputs , que está optimizada por el compilador, ya que no necesita ninguna cadena de formato) todavía sucede bajo el capó.
Si escribieras este programa en ensamblado puro, se vería así:
jmp start
msg db "Hello world\n"
start:
mov rdi, 1
mov rsi, offset msg
mov rdx, 11
mov rax, 1 ; write
syscall
xor rdi, rdi
mov rax, 60 ; exit
syscall
Lo que básicamente resulta en invocar la write llamada al sistema seguida por la exitllamada al sistema. Ahora, esto sería lo mínimo para lograr lo mismo.
Para resumir
C es mucho más básico , y solo hace lo mínimo necesario, dejando el control total al usuario, que puede optimizar y personalizar completamente todo lo que quiera. Le dice al procesador que cargue una cadena en un registro y luego llama a una función de biblioteca para usar esa cadena. C ++ por otro lado es mucho más complejo y abstracto . Esto tiene una enorme ventaja al escribir código complicado, y permite un código más fácil de escribir y más amigable para los humanos, pero obviamente tiene un costo. Siempre habrá un inconveniente en el rendimiento en C ++ si se compara con C en casos como este, ya que C ++ ofrece más de lo necesario para realizar tareas tan básicas y, por lo tanto, agrega más sobrecarga .
Respondiendo a tu pregunta principal :
¿Estoy pagando por lo que no estoy comiendo?
En este caso específico, sí . No está aprovechando nada de lo que C ++ tiene para ofrecer más que C, pero eso es solo porque no hay nada en ese simple código con el que C ++ pueda ayudarlo: es tan simple que realmente no necesita C ++.
¡Ah, y solo una cosa más!
Las ventajas de C ++ pueden no parecer obvias a primera vista, ya que escribió un programa muy simple y pequeño, pero mire un ejemplo un poco más complejo y vea la diferencia (ambos programas hacen exactamente lo mismo):
C :
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a, const void *b) {
return *(int*)a - *(int*)b;
}
int main(void) {
int i, n, *arr;
printf("How many integers do you want to input? ");
scanf("%d", &n);
arr = malloc(sizeof(int) * n);
for (i = 0; i < n; i++) {
printf("Index %d: ", i);
scanf("%d", &arr[i]);
}
qsort(arr, n, sizeof(int), cmp)
puts("Here are your numbers, ordered:");
for (i = 0; i < n; i++)
printf("%d\n", arr[i]);
free(arr);
return 0;
}
C ++ :
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void) {
int n;
cout << "How many integers do you want to input? ";
cin >> n;
vector<int> vec(n);
for (int i = 0; i < vec.size(); i++) {
cout << "Index " << i << ": ";
cin >> vec[i];
}
sort(vec.begin(), vec.end());
cout << "Here are your numbers:" << endl;
for (int item : vec)
cout << item << endl;
return 0;
}
Espero que puedan ver claramente lo que quiero decir aquí. Observe también cómo en C tiene que administrar la memoria en un nivel inferior usando mallocy freecómo debe tener más cuidado con la indexación y los tamaños, y cómo debe ser muy específico al tomar entradas e imprimir.