¿Cuáles son algunos conceptos / técnicas / características de lenguaje que todo programador decente de C debería conocer / conocer (excluir ingeniería de software general y similares y centrarse solo en cosas específicas de C)? Me gustaría saber para poder llenar algunos vacíos posibles en mi conocimiento de C.
Comience con las preguntas C de Stack Overflow y vea si hay algo que no sepa.
chrisaycock
3
Un programador de C probablemente debería saber que2 + 2 = 4
Edward Strange
21
Deben saber de una tienda que venda zapatos a prueba de balas.
Adam Crossland
1
Hay cientos de libros escritos sobre este tema. Tu pregunta es realmente bastante vaga. Tendrás que ser más específico para obtener respuestas decentes que no sean solo una lista de cosas. Y al ver las respuestas tan lejos de esta pregunta, creo que es necesario modificarla o cerrarla.
Walter
2
¿Otro lenguaje de programación?
Muhammad Alkarouri
Respuestas:
19
¿Específico para C? Además de las construcciones estándar comunes a la mayoría de los lenguajes de procedimiento, tendría que decir:
(ab) utilizando el preprocesador
enlazador vs compilador
Punteros Punteros Punteros!
Cómo las matrices son punteros son matrices
Cómo funcionan las cadenas C y cómo también son punteros y matrices
El mal uso de la cadena C puede provocar desbordamientos del búfer
Cómo lanzar cualquier cosa a cualquier cosa (todo es solo 1s y 0s después de todo :))
Gestión manual de memoria malloc / gratis
Pila vs Montón
Alias de puntero, (por qué es ilegal en C99)
Pensando en el desarrollo en términos de módulos (archivos .h / .c) con un conjunto de funciones expuestas públicamente en lugar de estrictamente clases
El programador de CA debe saber ... ¡otros idiomas! ;-) Siempre es fructífero conocer conceptos de otros lenguajes de varios paradigmas, como OOP, programación funcional, etc.
Más en serio, un vistazo al concurso de programación ofuscado es divertido y, curiosamente, también es una buena experiencia.
Mencioné "desbordamientos de búfer" en un comentario a la respuesta de Pythagras, probablemente debería aclarar un poco lo que quise decir. En C, no es suficiente saber que trabajar directamente con la memoria es peligroso; también debe comprender las formas precisas en que es peligroso. Realmente no me gusta la metáfora de "pegarse un tiro en el pie" para todos estos casos: muchas veces, no es que aprietas el gatillo, pero a menudo es un actor con intereses contrarios a los tuyos y / o de los usuarios .
Por ejemplo, en una arquitectura con una pila descendente (las arquitecturas más populares se ajustan a este proyecto de ley, generalmente se incluyen x86 y ARM), cuando se llama a una función, la dirección de retorno de la función se colocará en la pila después de las variables locales definidas en el cuerpo de la función. Entonces, si declara un búfer como una variable local y expone esa variable al mundo exterior sin verificar el desbordamiento del búfer, así:
void myFn(void){char buf[256];
gets(buf);}
un usuario externo puede enviarle una cadena que sobrescribe la dirección de retorno de la pila; básicamente, puede cambiar la idea de tiempo de ejecución de su programa del gráfico de llamadas que conduce a la función actual. Entonces, el usuario le da una cadena que es la representación binaria de algún código ejecutable para su arquitectura, suficiente relleno para desbordar la pila myFny algunos datos adicionales para sobrescribir la dirección de retorno para myFnque apunte al código que le dio. Si esto sucede, cuando myFnnormalmente hubiera devuelto el control a su interlocutor, en su lugar se ramificará al código que proporcionó el usuario malintencionado. Si escribe código C (o C ++) que tiene el potencial de exponerse a usuarios no confiables, debe comprender este vector de ataque. Debe comprender por qué un desbordamiento del búfer contra la pila es a menudo (pero no siempre) más fácilmente explotable que uno contra el montón, y debe comprender cómo se presenta la memoria en el montón (no con demasiados detalles, necesariamente, pero el La idea de que una malloc()región ed tiene estructuras de control que la rodean puede ayudar a comprender por qué su programa se bloquea en otra malloc()o en free()).
C lo expone a detalles de bajo nivel sobre cómo funciona su máquina, y le brinda un control más directo sobre su máquina que cualquier otro lenguaje editado por el usuario en uso generalizado hoy en día. Con un gran poder viene una gran responsabilidad: realmente necesita comprender esos detalles de bajo nivel para trabajar con C de manera segura y efectiva.
2 + 2 = 4
Respuestas:
¿Específico para C? Además de las construcciones estándar comunes a la mayoría de los lenguajes de procedimiento, tendría que decir:
fuente
Comprenda los punteros y comprenderá las computadoras.
fuente
Además de la excelente respuesta de pythagras,
cómo escribir (o al menos leer) declaraciones complicadas, como
char (*(*funcs[4])())[10]
funcs es una matriz [4] de punteros a una función que devuelve el puntero a la matriz [10] de caracteres
fuente
fuente
El programador de CA debe saber ... ¡otros idiomas! ;-) Siempre es fructífero conocer conceptos de otros lenguajes de varios paradigmas, como OOP, programación funcional, etc.
Más en serio, un vistazo al concurso de programación ofuscado es divertido y, curiosamente, también es una buena experiencia.
fuente
Mencioné "desbordamientos de búfer" en un comentario a la respuesta de Pythagras, probablemente debería aclarar un poco lo que quise decir. En C, no es suficiente saber que trabajar directamente con la memoria es peligroso; también debe comprender las formas precisas en que es peligroso. Realmente no me gusta la metáfora de "pegarse un tiro en el pie" para todos estos casos: muchas veces, no es que aprietas el gatillo, pero a menudo es un actor con intereses contrarios a los tuyos y / o de los usuarios .
Por ejemplo, en una arquitectura con una pila descendente (las arquitecturas más populares se ajustan a este proyecto de ley, generalmente se incluyen x86 y ARM), cuando se llama a una función, la dirección de retorno de la función se colocará en la pila después de las variables locales definidas en el cuerpo de la función. Entonces, si declara un búfer como una variable local y expone esa variable al mundo exterior sin verificar el desbordamiento del búfer, así:
un usuario externo puede enviarle una cadena que sobrescribe la dirección de retorno de la pila; básicamente, puede cambiar la idea de tiempo de ejecución de su programa del gráfico de llamadas que conduce a la función actual. Entonces, el usuario le da una cadena que es la representación binaria de algún código ejecutable para su arquitectura, suficiente relleno para desbordar la pila
myFn
y algunos datos adicionales para sobrescribir la dirección de retorno paramyFn
que apunte al código que le dio. Si esto sucede, cuandomyFn
normalmente hubiera devuelto el control a su interlocutor, en su lugar se ramificará al código que proporcionó el usuario malintencionado. Si escribe código C (o C ++) que tiene el potencial de exponerse a usuarios no confiables, debe comprender este vector de ataque. Debe comprender por qué un desbordamiento del búfer contra la pila es a menudo (pero no siempre) más fácilmente explotable que uno contra el montón, y debe comprender cómo se presenta la memoria en el montón (no con demasiados detalles, necesariamente, pero el La idea de que unamalloc()
región ed tiene estructuras de control que la rodean puede ayudar a comprender por qué su programa se bloquea en otramalloc()
o enfree()
).C lo expone a detalles de bajo nivel sobre cómo funciona su máquina, y le brinda un control más directo sobre su máquina que cualquier otro lenguaje editado por el usuario en uso generalizado hoy en día. Con un gran poder viene una gran responsabilidad: realmente necesita comprender esos detalles de bajo nivel para trabajar con C de manera segura y efectiva.
fuente
Además de las otras buenas respuestas, me gustaría agregar técnicas de programación defensiva a la lista.
Por ejemplo, usar afirmaciones al inicio / final de las funciones para verificar el contrato.
fuente