¿Por qué los sistemas operativos hacen cosas de bajo nivel en C y C ++? ¿Por qué no solo C ++?

20

En la página de Wikipedia para Windows , indica que Windows está escrito en ensamblado para el gestor de arranque y el conmutador de tareas, y C y C ++ para las rutinas del kernel.

IIRC, puede llamar a funciones C ++ desde un extern "C"bloque 'd. Puedo usar C para las funciones del núcleo, de modo que las aplicaciones de C puras puedan usarlas (me gusta printfy tal), pero si se pueden envolver en un extern "C "bloque, ¿por qué codificar en C?

Cole Johnson
fuente
10
¿Has visto los diversos "¿Por qué usar C cuando hay C ++?" preguntas aqui? Esto no es necesariamente un duplicado de ninguno de ellos, pero están relacionados.
1
"puede llamar a funciones de C ++ desde un bloque externo" C "'como C ++" ¿Quiere decir que puede llamar a funciones de C ...?
Code-Guru
@ Code-Guru no, porque la única diferencia entre las funciones exportadas de C y C ++ es la decoración del nombre y en C ++, la adición de la thisvariable
Cole Johnson
2
Lanza una excepción en un ISR y mira lo que sucede
James
Otra pregunta más de C vs. C ++.
Machado

Respuestas:

31

Es principalmente por razones históricas. Algunas partes del kernel de Windows se escribieron originalmente en C, porque en 1983, hace más de tres décadas, cuando se lanzó Windows 1.0 , C ++ apenas se lanzó. Ahora, estas bibliotecas C permanecerán allí "para siempre", ya que Microsoft convirtió la compatibilidad con versiones anteriores en un punto de venta y la reescritura de una versión compatible con errores de las partes C en C ++ requiere mucho esfuerzo sin ningún beneficio efectivo.

back2dos
fuente
+1, supongo que esa es la respuesta más realista (además del hecho de que puede haber algunos desarrolladores de kernel de Windows que simplemente no les gusta C ++ o no confían en los compiladores de C ++ para esas cosas de bajo nivel). Mire, por ejemplo, aquí stackoverflow.com/questions/520068/… , por qué el kernel de Linux está escrito en C.
Doc Brown
@ back2dos: si bien su código C no se descartará, eso no significa que se usará o no se actualizará. Le garantizo que hay al menos un método que hace algo que fue originalmente escrito y contenido dentro de una biblioteca C que ha sido portada como una biblioteca C ++ en Windows 8
Ramhound
8
Me cuesta creer que haya algún código de Windows 1.0 en cualquier versión reciente de Windows. Windows ME fue la última versión de Windows que no se basó en la base de código de Windows NT. E incluso eso ha sido reemplazado en gran medida por el nuevo núcleo RT (que, según tengo entendido, no promete mucho en cuanto a la compatibilidad con versiones anteriores).
TMN
@TMN: el argumento es más probable que sea correcta - Estoy bastante seguro en la carretera de Win 1.0 ahora no había una gran cantidad de bibliotecas escritas en C que siguen siendo parte de la corriente de base código de Windows 8, y nadie en MS ve ningún beneficio de reescribirlos en C ++.
Doc Brown
1
Casi no hay código que hable con el núcleo de Windows de todos modos. Básicamente, solo los conductores lo hacen. Las aplicaciones generalmente hablan con la API Win32, o posiblemente con la API POSIX.
MSalters
24

Como la mayoría de la gente ha señalado, las razones son con mucho históricas, pero hay algo más que nadie menciona y creo que es la razón por la que la gente todavía escribe código C para bajo nivel.

C es un lenguaje pequeño en el sentido de que la especificación es (relativamente) corta. C ++ es enorme y eso es insuficiente. Esto puede no importar mucho para el programador (aunque creo que sí), pero es extremadamente importante si desea hacer una verificación formal . Además, existen herramientas establecidas para el análisis de código C, que podrían ayudar a prevenir errores, etc.

Y esto es muy importante en el software embebido, donde el costo de un error que se implementa es extremadamente alto, en relación con el resto de la industria (compare Web, donde puede aplicar un parche de inmediato a todos los usuarios). Sin mencionar el software de misión crítica y el material médico.

Ha habido intentos de desplazar a C de su lugar dominante en la programación de bajo nivel con lenguajes que son aún mejores en esto, como BitC, pero hasta ahora no han tenido éxito.

K.Steff
fuente
44
+1 Por mencionar software de misión crítica en C puro (por ejemplo, software aeronáutico). Sin embargo, en el software médico también se usa C ++ (se usan pruebas exhaustivas en lugar de una verificación formal, lo que sería extremadamente difícil en C ++).
Giorgio
1
Además, C tiene un subconjunto seguro bastante exitoso MISRA-C. Hay equivalentes para C ++, pero no son estándar de facto de la industria (todavía). La tendencia en la programación crítica para la seguridad es que las bibliotecas y los compiladores también se verán obligados a usar un subconjunto seguro como MISRA. Reescribir una versión compatible con MISRA-C ++ de toda la biblioteca estándar de C ++ probablemente sea una pesadilla.
2
Las pautas de @Lundin MISRA no son un subconjunto seguro: todavía tiene punteros sin procesar y la mayoría de las otras características que hacen que C sea inseguro, se centran principalmente en no usar o documentar el comportamiento específico de la implementación.
Pete Kirkham
@PeteKirkham MISRA-C detectará todos los errores de puntero más clásicos y aplicará el análisis estático. Los estándares de seguridad de la industria (IEC 61508 et al) aparentemente aprueban MISRA-C como un subconjunto seguro de C. No hay muchas otras alternativas útiles para el software de misión crítica, a menos que elija SPARK Ada, un lenguaje que pocos conocen, con herramientas limitadas apoyo.
2
Esto debería haber sido seleccionado como la mejor respuesta, ya que es correcto. Otros que sugieren que C solo se usa por razones históricas son histéricos en sí mismos.
Rob
15
  1. El tiempo de ejecución C es mucho más pequeño.
  2. La traducción de C ++ en construcciones de nivel inferior es menos transparente que en C. (Ver referencias y vtables, para dos ejemplos rápidos)
  3. C generalmente tiene un ABI estable. C ++ generalmente no lo hace. Esto significa que, como mínimo, la interfaz de llamada del sistema debe ser de estilo C. Además, si desea algún tipo de módulos dinámicos, tener un ABI consistente es de gran ayuda.
wnoise
fuente
+1 para (2) y (3). No estoy convencido con (1).
Thomas Eding
77
@Thomas Eding: el tiempo de ejecución de C ++ consta del tiempo de ejecución de C, además de características de C ++ como excepciones, RTTI y otro asignador de memoria. YMMV en cuanto a si eso cuenta como mucho más grande. (Y luego está la biblioteca estándar ...)
wnoise
Ah, olvidé las excepciones y los grupos nuevos / eliminados. RTTI que nunca uso: D
Thomas Eding
11

Las razones no son técnicas. Un poco de ensamblaje es inevitable, pero no se ven obligados a usar la C ocasional, como lo desean . Mi empresa utiliza su propio núcleo patentado, escrito casi en su totalidad en C ++, pero no necesitamos admitir una interfaz C para el núcleo como la mayoría de los demás, porque nuestro núcleo integrado está compilado monolíticamente con nuestras aplicaciones C ++. Cuando tiene una interfaz C, a menudo es más fácil escribir el código de la interfaz en C, aunque es posible usarlo extern "C"para escribir en C ++.

Incluso tenemos un puñado de archivos C, principalmente debido a código de terceros. El código de bajo nivel de terceros casi siempre se proporciona en C, porque es mucho más fácil incorporar código C en una aplicación C ++ que al revés.

Karl Bielefeldt
fuente
6

Los desarrolladores del kernel son a menudo el tipo de personas, que se sienten más felices, cuando de inmediato se desprende de la fuente, lo que el código realmente hace.

C ++ tiene muchas más funciones, que ocultan lo que hace el código más de lo que el código C simple lo oculta: sobrecargas, métodos virtuales, plantillas, referencias, lanzamientos ... C ++ también tiene mucha más sintaxis que debe dominar para comprender incluso el C ++ código que lo usa.

Creo que el poder de C ++ es una herramienta muy poderosa para crear bibliotecas y marcos, que luego facilitan el desarrollo de aplicaciones. Muy a menudo, el desarrollador de aplicaciones C ++ se perdería totalmente en las entrañas llenas de plantillas de una biblioteca, incluso cuando es muy competente en la creación de aplicaciones utilizando esa biblioteca. Y escribir una biblioteca de C ++ correctamente es una tarea de programación muy desafiante, y solo se realiza para proporcionar un gran marco para el beneficio del desarrollador de aplicaciones. Las bibliotecas de C ++ no son internamente simples, son (o pueden ser ...) simplemente poderosas pero simples desde el punto de vista de los programadores de aplicaciones.

Pero la API del núcleo no puede ser una API de C ++, debe ser una API independiente del lenguaje, por lo que la mayoría de las cosas buenas de C ++ no serían directamente utilizables en esa interfaz. Además, el núcleo no está realmente dividido en partes de "biblioteca" y "aplicación" desarrolladas independientemente, con más esfuerzo yendo lógicamente a una biblioteca, para facilitar la creación de una gran cantidad de aplicaciones.

Además, la seguridad y la estabilidad son más críticas dentro de un núcleo, y los métodos virtuales son mucho más dinámicos y, por lo tanto, mucho más difíciles de aislar y verificar, que las devoluciones de llamada simples u otros mecanismos similares a C.

En resumen, si bien podría escribir cualquier programa en C, incluido un kernel como C ++, la mayor parte del poder de C ++ no se usa bien en el kernel. Y muchos dirían que las herramientas de programación deberían evitar que hagas cosas que no deberías hacer. C ++ no lo haría.

Hyde
fuente
+1. Como desarrollador de kernel, mi "regla de oro" es que si no puede estimar "tocar líneas de caché" fácilmente, entonces el lenguaje que está utilizando está haciendo más daño que bien.
Brendan
Aclaración: para los núcleos, debe suponer que la CPU pasa la mayor parte del tiempo en el espacio del usuario y el código del núcleo se usa esporádicamente (por ejemplo, cuando el espacio del usuario llama a la API del núcleo o se produce una interrupción); lo que significa que debe asumir "caché en frío". Para las CPU modernas (donde la RAM es lenta en relación con la velocidad de la CPU), los errores de caché y TLB son caros, por lo que (combinado con la expectativa de "caché en frío") la métrica "líneas de caché tocadas" se convierte en un indicador extremadamente importante para el rendimiento y / o la escalabilidad.
Brendan
5

Bjarne Stroustrup, en una entrevista en julio de 1999 :

Ninguno de estos idiomas era radicalmente diferente o dramáticamente mejor que otros idiomas contemporáneos. Sin embargo, fueron lo suficientemente buenos y los beneficiarios de la suerte y los factores sociales.

david
fuente
2
Bienvenido David Al citar o citar, es una buena idea proporcionar una referencia (¡agregado!)
Andrew
3

C es un lenguaje de muy bajo nivel, por su diseño. Está a un paso del ensamblador; conociendo el conjunto de chips al que se dirige, podría, con un poco de conocimiento, "compilar" C manualmente en ASM. Este tipo de lenguaje "cercano al metal" es clave para altos niveles de optimización (para rendimiento, eficiencia de memoria, etc.). Sin embargo, debido a que está tan cerca del metal, no obtienes mucho gratis con este lenguaje; es un lenguaje de procedimiento, no orientado a objetos, y por lo tanto trabajar con tales construcciones implica una gran cantidad de código repetitivo para crear y consumir construcciones de valores múltiples en la memoria.

C ++ es "C one better", agregando una serie de características fáciles de usar, como asignación dinámica de memoria, cálculo de estructura incorporado, una gran biblioteca de código predefinido, etc., a expensas de algunas pérdidas de eficiencia (aún mucho mejor que los entornos de tiempo de ejecución administrado). Para el codificador promedio, las ventajas superan con creces las desventajas en áreas de la base de código que no necesitan un control anal-retentivo de la asignación de memoria, etc.

La combinación de los dos es bastante tradicional; usa C para escribir las áreas de código base más eficientes en cuanto a rendimiento y memoria, con las que puede trabajar de manera más abstracta mediante llamadas a métodos del código C ++, que pueden organizarse y diseñarse de manera más elegante que el súper rendimiento , código C optimizado súper oogly.

KeithS
fuente
2
Con respecto a la eficiencia, me repetiré: (1) La gente de C ++ te dirá que es una mierda. (2) Estoy diciendo que no veo ninguna razón para que este sea el caso, y quisiera ejemplos concretos. No ejemplos de cómo es fácil escribir código menos eficiente, sino ejemplos de cómo ser tan eficiente como C requiere fealdad indebida.
3
Definir "feo"; Codifico en C # para ganarme la vida, y cada vez que veo ejemplos de código de C ++ en StackOverflow, me avergüenzo de cuánto se considera normal en el uso diario del lenguaje. Cuando codifiqué en C ++ hace mucho tiempo, a menudo veía código C y me encogía; tipos de estructura de embalaje manual, cálculos de puntero de ejecución para saltos manuales, ASM incrustado ... ¡qué asco! Algunas personas lamentan la pérdida de conocimiento de bajo nivel entre los programadores de Java / .NET; Lo considero una gran bendición para la productividad.
KeithS
1
No respondiste mi pregunta;) Por "feo" quiero decir "feo para los estándares de los gurús de C ++". En otras palabras, ejemplos en los que uno no puede usar "C ++ moderno" y ser tan eficiente como C.
2
Eso puede ser cierto (sinceramente, no lo sé). Sin embargo, para el desarrollo del kernel (y algunos otros campos), no estamos hablando de programadores promedio.
3
La gente olvida que C -> C ++ es un continuo. Con demasiada frecuencia, estos argumentos comparan C ++ bueno y moderno con C. Puede tomar un programa C y compilarlo con un compilador C ++ en un tiempo relativamente corto y se ejecutará exactamente igual de rápido. Si una característica moderna de C ++ es "demasiado lenta", no la use. Eso incluso puede incluir cosas como iostream. "Demasiado lento" nunca es una buena excusa para usar C sobre C ++.
Gort the Robot
1

Podría ser que con C pases la mayor parte de tu tiempo pensando en el problema en cuestión y cómo codificar la solución. En C ++ terminas pensando en C ++ y su miríada de características, funciones y sintaxis oscura.

También en muchas tiendas de C ++ su código es monitoreado por la "policía de la moda" que está cautivada por el último conjunto de patrones de diseño, o los últimos pronunciamientos ininteligibles del gran dios Stroustrup. El código bonito se vuelve más valioso que el código de trabajo, admirar el uso del último conjunto de plantillas de Boost es más admirable que encontrar una solución de trabajo para el negocio.

Mi experiencia es que, para todas las funciones inteligentes y la pureza OO de C ++, la codificación en C simple hace el trabajo de manera más rápida y efectiva.

James Anderson
fuente
0

Es posible que las partes C no sean muy portables para el compilador C ++ que se usa para las partes C ++. Tal vez el código C es amigable con el compilador de C en formas que rompen con el compilador de C ++.

Si tiene un compilador de C ++ de calidad, casi no hay razón para mezclar C y C ++ en un proyecto. Casi.

La única razón sería que su proyecto comparte código C con otros proyectos, el código no se compila como C ++ y no desea mantener una bifurcación C ++ de ese código.

Kaz
fuente
-1

Creo que lo tiene al revés: el extern "C"bloque garantiza que las convenciones de llamada C se utilicen para todas las funciones dentro del bloque. Por lo tanto, puede llamar a las funciones de C puro de C ++, no a las funciones de C ++ de C. Independientemente, me imagino que la razón por la que las personas usan C y C ++ es porque muchas bibliotecas de bajo nivel se escriben usando C, y es más fácil usar algo que ya existe (y presumiblemente está depurado y optimizado) que escribir el suyo propio. OTOH, C ++ ofrece muchas características agradables de alto nivel con las que las personas preferirían trabajar, por lo que las usan para el resto.

TMN
fuente
-2

Hay varios niveles de plataformas integradas que usan C como lenguaje de programación (por supuesto, es su libertad usar el lenguaje ensamblador en cualquier momento)

Para 'Nivel', estoy hablando del nivel de recursos internos de SRAM y ROM para un sistema.

Estas plataformas a veces tienen recursos limitados (por ejemplo, algunas plataformas 8051 solo tienen 128 bytes de SRAM de usuario).

No tiene sentido admitir la asignación dinámica de memoria con una cantidad tan pequeña de RAM. (nuevo / eliminar) o incluso malloc en C.

Una de las principales mejoras de C a C ++ es el paradigma orientado a objetos. C ++ es adecuado en software con mayor huella de memoria

pero no en firmware incorporado que tiene su limitación de tamaño de hasta 32 KB. (por ejemplo, en una plataforma MCU de 16 bits)

No es necesario tener un compilador de C ++ que generalmente es más complicado que el compilador de C. (al menos los proveedores de SDK no se molestarán en hacer esto).

De hecho, apenas puedo encontrar un compilador de C ++ en una plataforma ARM7 de 32 bits.

Simplemente no vale la complejidad

En algunos 8051 (8 bits): 1 MB de ROM, 128 B de RAM

TI MSP430 (16 bits): 32KB ROM, 4KB RAM

ST Microelectronics ARM 32-bit Cortex ™ -M3 CPU Core (STM32F103T4): 16 o 32 Kbytes de memoria Flash 6 o 10 Kbytes de SRAM

ansonchau
fuente
2
Esto no es nada nuevo para las otras respuestas ya publicadas aquí.
Martijn Pieters
¿Un compilador de C ++ de 32 bits para ARM? Si lo desea, puede compilar LLVM desde la fuente usted mismo después de algunas modificaciones para obtener un compilador de C ++ para iOS.
Cole Johnson
-4

Veo un par de posibles razones:

  • C es un poco más eficiente si se compara con el equivalente de C ++.
  • Algunas bibliotecas que usan están escritas en C.
  • Usan algunas partes del kernel de Linux, que está escrito en C.

Editado: Resulta que el tercer argumento no es verdadero (ver comentarios).

Pijusn
fuente
55
(1) La gente de C ++ pediría diferir. Y objetivamente no veo ninguna razón para que este sea el caso. (2) C ++ puede llamar al código C muy bien (ese es el punto principal de la compatibilidad con versiones anteriores y extern "C").
1
Si MS usa algunas partes del kernel de Linux, y el kernel de Linux es GPL, ¿eso no significaría que Windows también tendría que ser GPL?
TomJ
1
@TomJ en realidad es por eso que también se vieron obligados a donar un par de miles de líneas a Linux. + ¿Por qué crees que admiten el desarrollo de Linux?
Pijusn
2
@Pius Su punto es (y tiene razón AFAIK), si hubiera un código de GPL vinculado al kernel de Windows, todo el kernel tendría que ser GPL (siempre que no haya un acuerdo separado con los titulares de los derechos de autor).
@delnan, no estoy seguro de los detalles. No soy abogado, así que no puedo comentar sobre eso. Pero hubo un pequeño escándalo hace un par de años sobre esto. No estoy seguro, pero creo que podría haber sido el módulo de red sobre el que se trataba todo lo loco.
Pijusn
-4

Porque C es posiblemente un mejor lenguaje que C ++. Y debido a que parte del código fue escrito antes de que C ++ se hiciera popular y la gente no haya tenido una razón para reemplazarlo.

Y debido a que C ++ tiene muchas características que pueden romper su código si no tiene cuidado al usarlo en un núcleo.

Minthos
fuente
C ++ espera bibliotecas dinámicas? ¿Y qué es la memoria dinámica?
44
-1 para [stuff] that C++ expects. ¿Por qué C ++ usa más montón que C? ¿Por qué C ++ requiere más dlls que C? Simplemente NO ES VERDADERO
Thomas Eding
1
Corrección: pierde las bibliotecas que están escritas en C ++. Por lo tanto, vuelve al cuadrado 1 si está usando C ++ o C. ¿Por qué limitarse a la funcionalidad C si puede usar plantillas, clases, destructores, constantes y todo tipo de otras bondades?
Thomas Eding
66
¿Qué? Las plantillas, las excepciones, los objetos (incluidos los constructores, los destructores, los operadores sobrecargados, ahora mover la construcción y, prácticamente, todo lo demás), etc. funcionan bien, independientemente de dónde provenga la memoria (pila, memoria estática, su grupo personalizado o lo que sea) . Los contenedores estándar usan la asignación de almacenamiento dinámico de forma predeterminada, pero sus asignadores se pueden personalizar y los encargados del núcleo escriben sus propias colecciones y gestión de memoria de todos modos. -1
2
FYI: Eliminé mi voto negativo porque no creo que tu respuesta sea activamente dañina por ahora, pero tampoco lo considero particularmente útil o perspicaz.