2009-04-06 8 views
15

En los podcasts Stack Overflow, Joel Spolsky constantemente le dice a Jeff Atwood que Jeff no sabe cómo escribir código en C. Su afirmación es que "conocer C le ayuda a escribir mejor código". También siempre usa algún tipo de historia que involucra la manipulación de cuerdas y cómo saber C le permitirá escribir rutinas de cuerdas más eficientes en un idioma diferente.¿Cuál es un ejemplo en el que conocer C me hará escribir mejor código en cualquier otro idioma?

Como alguien que sabe un poco de C, pero le encanta escribir código en Perl y otros lenguajes de alto nivel, que nunca han llegado a través de una vez un problema que yo era capaz de resolver por escrito C.

soy buscando ejemplos de situaciones del mundo real donde el conocimiento de C sería útil al escribir un proyecto en un lenguaje de alto nivel/dinámico como perl o python.

Editar: Al leer algunas de las respuestas que ustedes han presentado han sido grandes, pero aún no tiene ningún sentido para mí en este sentido:

Tomemos el ejemplo strcat. Hay una forma correcta y una incorrecta de combinar cadenas en C. Pero, ¿por qué debería (como desarrollador de alto nivel) pensar que soy más inteligente que Larry Wall? ¿Por qué los diseñadores de idiomas no escribirían el código de manipulación de cadenas de la manera correcta?

+1

"¿Por qué los diseñadores de idiomas no escribirían el código de manipulación de cadenas de la manera correcta?" Esto no tiene mucho sentido en general; y no tiene ningún sentido en el contexto de la programación C. Quizás esta debería ser una pregunta completamente diferente, una que se reescribe para ser más clara sobre qué cosa específica quieres saber. –

Respuesta

23

El ejemplo clásico que utiliza Joel Spolsky es en misuse of strcat and strlen, y detecta algoritmos de "Shlemiel el pintor" en general.

No es que necesite C para resolver problemas que los lenguajes de alto nivel no pueden resolver, sino que saber C le da una perspectiva de lo que sucede debajo de todos los niveles de idiomas que le permite escribir un mejor software. Porque esa perspectiva te ayuda a evitar escribir código que, para ti, es desconocido, en realidad O (n^2), por ejemplo.

Editar: Algunas aclaraciones basadas en comentarios.

Conocer C no es un requisito previo para tal conocimiento, hay muchas maneras de adquirir el mismo conocimiento.

Conocer C tampoco es una garantía de estas habilidades. Puede dominar C y aún así escribir un código horrible, sucio y pesado en cualquier otro idioma que toque.

C es un lenguaje de bajo nivel, sin embargo, todavía tiene estructuras de control y funciones modernas para que no siempre quede atrapado en los detalles. Es muy difícil llegar a ser competente en C sin obtener un dominio de ciertos fundamentos (como los detalles de la gestión de la memoria y los indicadores), el dominio de que a menudo rinde grandes dividendos cuando se trabaja en cualquier idioma.

Siempre se trata de los fundamentos.

Esto es cierto en muchas actividades, así como en la ingeniería de software. No son los encantamientos secretos los mejores programadores, sino el dominio de los fundamentos. La experiencia ha demostrado que el conocimiento de C tiende a tener una mayor correlación con el dominio de algunos de esos fundamentos, y que el aprendizaje de C tiende a ser una de las rutas más fáciles y más comunes para adquirir dicho conocimiento.

+0

derecha. para hacer grandes programas, necesitas una imagen completa, y un lenguaje de alto nivel es una gran parte de ello. si no conoces C (o incluso mejor, montaje) te pierdes esa parte. – Javier

+0

Conocer C no es un requisito previo para identificar un algoritmo Sclemiel. Hace 8 años, cuando solo tenía 3 años de experiencia, transfería 0.5 millones de registros de una tabla Oracle a una tabla MySQL usando Perl/DBI, identificaba mi propio algoritmo Shlemiel, lo arreglaba y movía todos los registros en 0.5 horas –

+0

No está diciendo que sea un requisito previo, solo que C puede ayudarte a ver esas cosas. –

3

Es difícil cuantificar exactamente, pero tener una comprensión de C le dará más información sobre cómo se implementan las construcciones de lenguaje de alto nivel y, como consecuencia, podrá utilizar mejor las construcciones de una manera inteligente.

+0

Estoy de acuerdo con usted al 100%, excepto que lo que estoy buscando es un ejemplo concreto de cómo sería útil. Joel Spolsky (en el podcast) siempre afirma que le permitirá escribir un código más eficiente o algo así. Eso es lo que trato de descubrir. –

3

Para darle una razón específica: tener que escribir mis propias rutinas de recolección de basura me ayudó a escribir mejor código.

No creo que haya encontrado un problema que no he podido resolver con un lenguaje de alto nivel; pero comencé aprendiendo C, me ha inculcado un buen número de excelentes prácticas de desarrollo. Saber cómo funcionan las partes rudimentarias del flujo de una aplicación le permitirá ver su propio código y obtener una buena visión de cómo fluyen los datos y dónde se almacenan. Esto lleva a una mejor comprensión de cómo rastrear la fuga de memoria, lentas lecturas de disco, cachés mal construidos, etc.

Seguir la pista de los punteros ... es otra cosa que me viene a la mente.

+0

punteros son vilipendiados; pero son las ruedas de la bicicleta de la CPU. – Javier

+0

Aquí hay un problema que no puede resolver con un lenguaje de nivel superior: toqueteo de bits en Lua –

2

Ejemplos clásicos son cosas que implican menor gestión de memoria de nivel, tales como la implementación de una clase de lista enlazada:

struct Node 
{ 
    Data *data; 
    Node *next; 
} 

La comprensión de cómo se utilizan los punteros para recorrer la lista y lo que significan en términos de la la arquitectura de la máquina le permitirá comprender mejor su código de alto nivel.

Otro ejemplo al que Joel se refería era la implementación de la concatenación de cadenas, y la forma correcta de crear una cadena a partir de un conjunto de datos.

// this is efficient 
for (int i=0; i< n; i++) 
{ 
    strcat(str, data(i)); 
} 

// this could be too, but you'd need to look at the implementation to be sure 
std::string str; 
for (int i=0; i<n; i++) 
{ 
    str+=data(i); 
} 
+2

strcat en un bucle así es un ejemplo de una forma realmente ineficaz de construir una cadena. Con las cadenas en C, querrá esperar hasta el final de la cadena después de cazarla, para que no tenga que volver a encontrarla, en un caso como el de su ejemplo. El ciclo std :: string es probablemente _más_ eficiente. –

+0

Sí, sí, estaba pensando desde el punto de vista que no necesitaría realizar asignaciones adicionales –

+0

Supongo que al menos estas discusiones ayudan a demostrar el punto :) –

0

lo veo de esta manera, todo se reduce a un nivel C en multiplataforma, y ​​el montaje de una manera específica de la plataforma. Así que es como ser un corredor de Rally de todo el país, y C es mecánica automotriz básica, puedes ser un gran piloto, pero cuando tienes problemas para saber C significa que probablemente puedas volver a la carrera, si no estás atrapado llamando a los mecánicos . Y el ensamblaje es lo que los mecánicos y los fabricantes saben, es una inversión valiosa si eso es lo que quieres hacer, de lo contrario, puedes confiar en la mecánica.

Para obtener detalles específicos pensar en la gestión de memoria, controladores de Hardwar, motores de física, de alto rendimiento de gráficos en 3D, pilas TCP, protocolos binarios, software integrado, la creación de lenguajes de alto nivel como Perl

1

¿Utiliza matrices tanto? y te encuentras con situaciones en las que necesitas almacenar elementos en la memoria sin saber cuántos de ellos (es decir, basados ​​en una consulta de la base de datos?) entonces supongo que C te enseñaría cosas geniales como pilas, estructuras y listas de enlaces que podrían ayudarte. Saludos, Andy

1

Conocer C realmente no vale mucho. A muchos de los que conocemos profundamente a C nos gusta pensar que toda esa profunda percepción es valiosa e importante.

Algunos de los que conocemos C no podemos pensar en una característica específica de C que sea útil conocer.

Saber cómo funcionan los punteros en C (especialmente con la sintaxis de C) no es tan útil. En un lenguaje de alto nivel tus declaraciones crean objetos y administran su interacción. Los indicadores y referencias son, tal vez, interesantes desde un punto de vista hipotético. Pero el conocimiento no tiene un impacto práctico sobre cómo usar Java o Python.

Los idiomas de nivel superior son como son. Sabiendo cómo no cambia esos idiomas; no cambia la forma en que los usa, los depura o prueba.

Saber cómo crear o manipular una lista vinculada no tiene ningún impacto en la definición de la clase de lista de Python. Ninguna.

Conocer la diferencia entre Lista enlazada y Lista de arreglos puede ayudarlo a escribir un programa Java. Pero la implementación de C no le ayuda a elegir entre Lista enlazada y Lista de arreglos. La decisión es independiente de saber C.

Un mal algoritmo es malo en todos los idiomas. Conocer los misterios internos de C no hace que un mal algoritmo sea menos malo. Conocer C no lo ayuda a conocer las colecciones Java o los tipos incorporados de Python.

No veo ningún valor en aprender C. Aprender Fortran es igual de valioso.

+0

"Un mal algoritmo es malo en todos los idiomas". a la derecha, y conocer C le permite identificar qué algoritmos utiliza un lenguaje de alto nivel bajo el capó, lo que le permite tomar la decisión correcta. sin C, solo se quedan con los documentos de idioma, que casi nunca los menciona (solo diga que son "lo suficientemente rápidos") – Javier

+3

¿Cómo puede un programador de Java ser eficaz sin saber qué referencias son y al menos un poco de cómo ¿trabajan? Sin ese conocimiento, incluso entender la diferencia entre someString.equals (someOtherString) y (someString == someOtherString) se vuelve bastante difícil. –

+0

Saber qué referencias son importantes. Saber C no es una forma de aprender eso. Puede aprender eso con las mismas imágenes simples que los programadores C usaron cuando estaban aprendiendo C. C en sí no ayuda. –

2

Conocer C le ayuda a escribir un mejor código en C. Supongo que el ejemplo de Joel Spolsky es de poca utilidad en C++ o Objective-C donde existen clases específicas para manipular cadenas y se han diseñado teniendo en cuenta el rendimiento. Además, el uso de trucos en C en otros idiomas puede ser productivo.

Sin embargo, el conocimiento de C es muy útil para comprender conceptos generales en otros idiomas y lo que hay detrás del capó en muchas situaciones.

8

Es un error asumir que aprender C de alguna manera automáticamente le dará una mejor comprensión de las preocupaciones de programación de bajo nivel. En muchos casos, incluso C es de un nivel demasiado alto para que comprenda bien los problemas de eficiencia.

Un clásico es i ++ versus ++ i. Está sobre-citado, así que quizás la mayoría de la gente conozca las implicaciones sobre el rendimiento entre estas dos operaciones. Pero aprender C no te enseñaría mágicamente esto por sí mismo.

Supongo que entiendo los argumentos sobre cadenas. Cuando las operaciones con cuerdas se hacen engañosamente simples, las personas a menudo las usan de manera ineficiente. Pero, de nuevo, saber que strncat existe no le da una apreciación completa de las preocupaciones sobre la eficiencia. Muchos programadores de C probablemente ni siquiera hayan pensado en el hecho de que strncat tiene que realizar una operación de strings internamente.

Incluso con C, es importante entender lo que sucede detrás de escena si la eficiencia es una preocupación. Las personas que conocen C tienden a ver las cosas en una progresión. El ensamblado y el código de máquina son los bloques de construcción de C, mientras que C es un bloque de construcción de lenguajes de nivel superior.

Esto no es específicamente cierto, pero es obvio que C está "más cerca del metal" que muchos lenguajes de nivel superior. Esto tiene al menos dos efectos: los problemas de eficiencia no están tan ocultos detrás del comportamiento implícito, y es más fácil equivocarse.

Así que quiere un ejemplo específico de cómo saber C le da una ventaja. No creo que haya uno. Creo que la gente significa cuando dicen que esto es que saber lo que está sucediendo detrás de escena en cualquier idioma en el que estés escribiendo te ayuda a tomar decisiones más inteligentes sobre cómo escribir código. Sin embargo, es un error asumir que C es "lo que está sucediendo detrás de escena" en Java, por ejemplo.

+0

Ojalá pudiera darle una respuesta más de una vez ... Esta es la mejor respuesta que he visto sobre este tema. – Jonas

0

No se puede escribir un núcleo del sistema operativo en Perl; C sería una opción mucho mejor para eso, porque es de bajo nivel suficiente para expresar todo lo que el kernel debería hacer, y lo suficientemente portátil para permitirle portar su kernel a diferentes arquitecturas

+0

Sí, pero no estoy tratando de escribir un kernel en Perl. Solo estoy tratando de hacer mi trabajo. Ya conozco a C, pero nunca me encontré con una situación en la que estaba escribiendo Perl y pensé: "Mierda, debería escribir esto en C". Siempre asumo que Larry Wall es más inteligente que yo. –

0

Conocer C no es un requisito para poder usar efectivamente lenguajes de alto nivel, pero ciertamente puede ayudar a los demás a comprender cómo funcionan las computadoras y el software; creo que es similar a la afirmación de que conocen algún lenguaje ensamblador o arquitectura de computadora/lógica de hardware (y/o/nand puertas, etc.) puede ayudar a un programador en C a ser un mejor programador.

A veces, para resolver un problema, es útil saber cómo funcionan las cosas "debajo" de lo que está haciendo.

No creo que esto signifique que un programador debe saber C para ser un buen programador, pero creo que conocer C puede ser útil para casi cualquier programador.

0

Sin saber Perl así, me pregunto si ahora es posible distribuir la carga del procesador a más de un núcleo físico con varios subprocesos creados en un solo programa en Perl, sin desove procesos adicionales

0

no lo hago Piensa que puede haber un ejemplo específico.

Lo que C hace por usted es darle una idea, un ensanchamiento de la mente, a cómo funcionan las computadoras (y el software). Es una cosa muy abstracta ..

No hace escribir mejor código en python, simplemente te hace más científico de la computación.

La referencia que hizo Wedge al artículo de Joel al mencionar a Shlemiel el pintor es interesante pero no tiene relevancia aquí. Ese algoritmo no está vinculado a C de ninguna manera en particular (aunque se manifiesta en cadenas terminadas en nulo).

Las cadenas de Python son inmutables de todos modos, y completamente diferentes del modelo de cadenas de C, por lo que no veo la relación.

Supongo que un ejemplo concreto es la optimización de un analizador o un lector o un programa que mantiene escribiendo en un búfer de cadena todo el tiempo. Si usa cadenas normales en lugar de un búfer de cadenas, se encontrará con un problema cuando construya cadenas de caracteres muy grandes.

considerar que:

a = a + b 

hace una copia de ambos a y b. No cambia la cadena a la que hizo referencia a, crea una nueva cadena, asignando más memoria, etc.

Si a se vuelve considerablemente grande, y usted sigue agregando cosas pequeñas, entonces Shlemiel, el pintor, manifestará él mismo.

Pero, una vez más, saber esto no tiene nada que ver con conocer C, simplemente saber cómo su lenguaje implementa las cosas en el nivel bajo. (Aquí es donde tener una experiencia en C te ayudará).

0

Técnicamente, todas las deficiencias de C lo obligarían a codificarlas; haciéndote escribir más código -> haciéndote más experimentado en general. Al carecer de cualquier entero portátil de más de 32 bits, C, en el pasado, me hizo escribir mi propia biblioteca bignum. La falta de administración implícita de memoria, recursos y errores (recolección de basura, RAII, constructores/destructores llamados automáticamente, excepciones) obligan a los usuarios de C a escribir mucha inicialización, manejo de errores y código de limpieza. Puede que sea solo yo, pero nunca me canso de escribir ese código. Voy y leo la documentación de cada función externa que llamo, vuelvo a mi código y verifico cada valor de retorno y otras cosas indicativas de fallas. ¡Incluso me hace sentir seguro!

Este último punto es probablemente el más grande que se hizo a favor del argumento.¡Solo puede escribir tantos pares de malloc()/free() antes de comenzar a analizar el tiempo de vida de cada variable individual que encuentra en cada idioma! Los objetos de almacenamiento automático de C++ tampoco ayudan a este trastorno.

Escribir código C verdaderamente portátil a menudo requiere que el programador no tenga muchas suposiciones sobre el sistema host - piense sizeof(), CHAR___BITS, unsigned long, UINT_MAX. Si bien esto no me ha ayudado a escribir un mejor código en otros idiomas, me ha ayudado a pensar en posibles implementaciones alternativas: cómo un pequeño microprocesador aún podría ejecutar mi código C, generando un montón de instrucciones RISC para mi declaración simple de una línea. (Eso es otra cosa, no hay muchos otros lenguajes que se asocien con un lenguaje de ensamblaje tan fácil en mi cabeza.) De nuevo, puedo ser yo mismo).

Por supuesto, ninguno de estos argumentos es solo para C. @ S.Lott tiene un punto válido: Fortran podría ser una alternativa igualmente buena. ¡Pero hay tanto código C alrededor! Todo un sistema de computadora personal de arriba a abajo -aplicaciones para las librerías para los controladores para kernel- está disponible en el código fuente en C. Sería un desperdicio si no pudieras leerlo.

0

En Python, supongamos que tiene una función

def foo(l=[]) 
    l.append("bar") 
    return l; 

En alguna versión de Python, disponible de hace un año, se ejecuta foo() para los tiempos, se obtendría un resultado realmente interesante (es decir ["bar","bar","bar","bar]) .

Parece que alguien implementó los parámetros predeterminados como una variable estática (y sin restablecerlo), por lo que se producen resultados inesperados.

Quizás mi ejemplo fue ideado: un amigo mío que realmente le gusta Python encontró este error peculiar, pero el hecho es que todos estos lenguajes se implementan en C o C++. Si no conoces y no entiendes los conceptos que son fundamentales para el lenguaje base, significa que no tendrás una comprensión profunda de los lenguajes que se construyen sobre eso.

Encuentro todo el "por qué molestarse con C/C++/ASM pregunta tonta". Si estás lo suficientemente inclinado como para aprender un idioma, eso significa que eres lo suficientemente curioso como para entrar en él en primer lugar. ¿Por qué parar justo antes de C?

0

Conocer C es excelente porque no hace nada detrás de su espalda (GC, comprobación de límites, etc.). Solo hace exactamente lo que tú le dices. Nada está implícito. Incluso C++ hace cosas que no se dicen con RAII (por supuesto, se da a entender que el objeto se destruye cuando se sale del alcance, pero en realidad no se escribe). C es una gran manera de aprender lo que sucede debajo del capó de la computadora, sin tener que escribir el ensamblaje.

2

Como alguien que sabe un poco de C, pero le encanta escribir código en Perl y otros lenguajes de alto nivel, que nunca han llegado a través de una vez un problema que yo era capaz de resolver por escrito C.

I Estoy buscando ejemplos de situaciones del mundo real donde el conocimiento de C sería útil al escribir un proyecto en un lenguaje de alto nivel/dinámico como Perl o Python.

Es fácil comenzar a escribir código de alto nivel y luego nos preguntamos si se está ejecutando lentamente. La verdad es que hay muchas maneras de escribir código perl o python, y algunas son mejores (como en el caso de las más eficientes) que las demás. Si conoce los detalles de bajo nivel de cómo se ejecuta su código en perl o python (ambos escritos en C), puede codificar varias ineficiencias, como saber qué constructo de bucle es más rápido, cómo se retiene/libera la memoria, etc. .

Además, cuando se escribe un proyecto en perl o python, a veces se llega a un muro de rendimiento.Los creadores del lenguaje (Guido, al menos) recomiendan que implemente esa parte en C, como extensión de idioma. Para hacer eso, bueno, tendrás que saber C.

Así que, allí.

0

código ineficiente (por ejemplo, bucles de cadena + =) suelen ser ineficientes en cualquier idioma. ¿Qué diferencia hay si alguien explica por qué es ineficiente en un idioma u otro? conocer a C, pero no darse cuenta de que un método es ineficiente, no es diferente de conocer Python y no darse cuenta de lo mismo.

2

A los efectos de argumentación, suponga que desea concatenar las representaciones de cadena de todos los números enteros de 1 a n (por ejemplo n = 5 produciría la cadena "12345"). Así es como uno podría hacer eso ingenuamente en, digamos, Java.

String result = ""; 
for (int i = 1; i <= n; i++) { 
    result = result + Integer.toString(i); 
} 

Si se va a reescribir ese segmento de código (que es en Java bastante buen aspecto-) en C lo más literalmente posible, se llega a algo para que la mayoría de los programadores de C se encogen de miedo:

char *result = malloc(1); 
*result = '\0'; 
for (int i = 1; i <= n; i++) { 
    char *intStr = malloc(11); 
    itoa(i, intStr, 10); 
    char *tempStr = malloc(/* some large size */); 
    strcpy(tempStr, result); 
    strcat(tempStr, intStr); 
    free(result); 
    free(intStr); 
    result = tempStr; 
} 

Dado que las cadenas en Java son inmutables, Integer.toString crea una cadena ficticia y la concatenación de cadenas crea una nueva instancia de cadena en lugar de alterar la antigua. Eso no es fácil de ver simplemente mirando el código de Java. Saber cómo dicho código se traduce en C es de una manera de aprender exactamente qué tan ineficiente es dicho código.

0

creo que vale la pena conocer algunos lenguaje de bajo nivel, y hay pragmáticos razones para elegir C:

  • Es de bajo nivel, cerca de ensamblador
  • Es generalizada

Comprender toda la pila es valioso. A veces necesitas depurar las agallas de algo. A veces no se puede solucionar un problema de rendimiento sin conocimientos de bajo nivel (esto es a menudo no el caso, por ejemplo, cuando el problema de rendimiento es puramente algorítmico, pero a veces sí).

¿Por qué es C ampliamente considerado el quintaesencia "fondo de la pila", y no algunos otros idiomas? Creo que esto porque C es un lenguaje de programación de bajo nivel, yC ganó. Ha pasado un tiempo, pero C no siempre fue tan dominante. Para tomar solo un ejemplo famoso, los proponentes de Common Lisp (que tenía sus propias formas de escribir código de bajo nivel) esperaban que su lenguaje también fuera popular, y eventualmente lost.

La siguiente normalmente se implementan en C:

sistemas operativos
  • (variantes de Unix, Windows, muchos sistemas operativos integrados) lenguajes de programación
  • de nivel superior (muchas implementaciones populares de Java, Python, etc.)
  • (obviamente) resmas de proyectos de código abierto populares

no soy una persona de hardware, pero tengo entendido que C ha influido en el diseño de la CPU en gran medida, también.

Así que si crees en la comprensión de toda la pila, aprender C es, desde una perspectiva pragmática, la mejor opción.

Como advertencia, creo que también vale la pena aprender ensamblador. Aunque C está cerca del metal, no entendí completamente C hasta que tuve que hacer un ensamblador. A veces es útil comprender cómo se realizan realmente las llamadas a las llamadas, cómo se implementan los bucles for, etc. Menos importante, pero también útil, es tener que lidiar (al menos una vez) con un sistema sin memoria virtual. Al usar C en Windows, Unix y algunos otros sistemas operativos, incluso el humilde malloc hace un montón de trabajo bajo las cubiertas que es más fácil de apreciar, depurar y/o sintonizar si alguna vez tuvo que lidiar con el bloqueo y desbloqueo manual de la memoria regiones (¡no es que yo recomendaría hacerlo de forma regular!)

Cuestiones relacionadas