En segundo lugar, esta especialidad requiere que tengas cierta comprensión de las redes móviles inalámbricas, como la estructura básica de la red, las teorías básicas y los conceptos básicos. Pero no es necesario ser competente, porque depende de la dirección que esté tomando cuando ingrese a la industria, como 2g o 3g.
Nuevamente, es necesario tener conocimientos básicos de informática, preferiblemente una computadora portátil, que es el estándar para la optimización de redes. Saber utilizar Excel será muy importante en campos de nivel medio y alto como la optimización de redes y bases de datos. Sería mejor si se pudiera realizar una programación sencilla más adelante. Este es un requisito para los expertos.
Por último, debes ser capaz de soportar las dificultades, poder viajar durante largos períodos de tiempo y ser capaz de adaptarte a las duras condiciones.
Además, si puedes hacer esa pregunta, ve a foros profesionales y mira lo que todos dicen. Se recomienda utilizar mscbsc y c114.
Preguntas de prueba de redacción de ingenieros de software
#define segundos/año (60 * 60 * 24 * 365)UL
Me gustaría ver algo aquí:
1).#Defina los conceptos básicos de la sintaxis (como no terminar con punto y coma, el uso de paréntesis, etc.)
2) Sepa que el preprocesador calculará expresiones constantes para usted valora, por lo que es más claro y menos costoso simplemente escribir cómo calculó la cantidad de segundos en un año en lugar de calcular el valor real.
3). Reconozca que esta expresión desbordará un entero de máquina de 16 bits; por lo tanto, utilice el símbolo de entero largo L para indicarle al compilador que la constante es un entero largo.
4) Si usa UL (unsigned long) en la expresión, entonces tiene un buen punto de partida. Recuerde, las primeras impresiones cuentan.
2. Escribe una macro MIN "estándar" que tome dos argumentos y devuelva el más pequeño.
#define MIN(A,B)((A)<= (B) (A) : (B))
Esta prueba está diseñada para lograr los siguientes propósitos:
1). Identificar los conocimientos básicos de la aplicación #define en macros. Esto es importante porque antes de que el operador en línea se convirtiera en parte del lenguaje C estándar, las macros eran la única forma de generar código en línea de manera conveniente. Para los sistemas integrados, el código integrado suele ser necesario para lograr el rendimiento requerido.
2). Conocimiento de tres operadores condicionales. Este operador existe en C porque permite al compilador generar código más optimizado que if-then-else. Es importante comprender este uso.
3). Saber encerrar cuidadosamente los parámetros entre paréntesis en las macros.
4). También utilizo esta pregunta para discutir los efectos secundarios de las macros, como por ejemplo: ¿Qué pasará si escribes el siguiente código?
least = MIN(*p++, b);
3. ¿Cuál es el propósito del identificador del preprocesador #error?
Si no sabes la respuesta, consulta la referencia 1. Esta pregunta es útil para diferenciar a los tipos normales de los nerds. Sólo un nerd leería el apéndice de un libro de texto en lenguaje C para descubrir algo como esto.
La respuesta a la pregunta. Por supuesto, si no estás buscando un nerd, es mejor que el candidato no sepa la respuesta.
Bucle infinito (bucle infinito)
4. Los bucles infinitos se utilizan a menudo en sistemas integrados. ¿Cómo escribir un bucle infinito en lenguaje C?
Existen varias soluciones a este problema. Mi primera opción es:
while(1) { }
Algunos programadores prefieren la siguiente solución:
for(;;) { }
Esta implementación me avergüenza porque la sintaxis no expresa exactamente lo que está pasando. Si un candidato tiene esto como plan, lo aprovecharía como una oportunidad para explorar lo que hace.
Principios básicos. Si su respuesta básica es: "Me enseñaron a hacer esto, pero nunca pensé por qué", eso me deja una mala impresión.
La tercera opción es utilizar goto.
Bucle:
...
Ir al bucle;
Si el candidato da la solución anterior, significa que está ya sea programadores de lenguajes compiladores (lo cual probablemente sea algo bueno) o programadores de BASIC/FORTRAN que quieran ingresar a un nuevo campo.
Declaración de datos (declaración de datos)
5. Utilice la variable A para dar la siguiente definición
a) Entero.
b) Puntero a número entero.
c) Puntero a puntero, puntero a entero (puntero a entero)
d) Array de 10 enteros.
e) Hay una matriz de 10 punteros y el puntero apunta a un número entero (10 punteros apuntan a una matriz de números enteros).
f) Puntero a una matriz de 10 números enteros.
g) Un puntero a una función que toma un argumento entero y devuelve un número entero (un puntero a una función que toma un número entero como argumento y devuelve un número entero).
h) Una matriz con 10 punteros que apuntan a una función que toma un parámetro entero y devuelve un número entero (una matriz de diez punteros apunta a una función que toma un parámetro entero y devuelve un número entero).
La respuesta es:
a)int a; //entero
b)int * a; //puntero a entero
>c)int * * a; //Puntero a puntero entero
d)int a[10] //Matriz de 10 enteros
e)int * a[ 10] ; //Matriz de 10 punteros a números enteros
f)int(* a)[10] //Puntero a matriz de 10 números enteros
g)int( * a)( int); //Puntero a la función A que toma parámetros enteros y devuelve un número entero
h)int(* a[10])(int); //Matriz de 10 punteros. Estos punteros apuntan a funciones. que toman argumentos enteros y devuelven números enteros
La gente suele afirmar que aquí hay varias preguntas que sólo pueden responderse leyendo un libro. Estoy de acuerdo con esta afirmación. Mientras escribía esto, consulté el libro para asegurarme de que la gramática fuera correcta.
Pero durante la entrevista, esperaba que me hicieran esta pregunta (o una pregunta similar). Porque durante la entrevista definitivamente supe la respuesta a esta pregunta. Si el candidato no sabe todas las respuestas (o al menos la mayoría de las respuestas), entonces no está preparado para la entrevista. Si el entrevistador no se preparó para esta entrevista, ¿por qué debería hacerlo?
Estático
6. ¿Cuál es la función de la palabra clave estática?
Pocas personas pueden responder completamente a esta sencilla pregunta. En lenguaje C, la palabra clave static tiene tres funciones obvias:
1). En el cuerpo de la función, una variable declarada como estática mantiene su valor sin cambios durante la llamada de la función.
2) Dentro del módulo (pero fuera de la función), las funciones utilizadas en el módulo pueden acceder a las variables declaradas como estáticas, pero otras funciones fuera del módulo no pueden acceder a ellas. Es una variable global local.
3) En un módulo, las funciones declaradas como estáticas solo pueden ser llamadas por otras funciones del módulo. Es decir, la función está restringida al ámbito local del módulo en el que se declara.
La mayoría de los candidatos pueden responder correctamente la primera parte, algunos pueden responder correctamente la segunda parte y pocos pueden entender la tercera parte. Esta es una deficiencia grave por parte de un candidato que claramente no comprende los beneficios y la importancia de localizar los alcances de los datos y el código.
Constante
7. ¿Qué significa la palabra clave constante?
Tan pronto como escuché al entrevistado decir "const significa sin cambios", supe que estaba tratando con un profano. El año pasado, Dan Saks resumió completamente todos los usos de const en su artículo, por lo que cada lector de ESP (Traductor: Programación de sistemas integrados) debería estar muy familiarizado con lo que const puede y no puede hacer. Si nunca ha leído el artículo, simplemente diga que const significa "solo lectura". Aunque esta respuesta no es una respuesta completa, la acepto como la respuesta correcta. Si desea obtener una respuesta más detallada, lea atentamente el artículo de Sacks.
Si el candidato puede responder esta pregunta correctamente, le haré una pregunta adicional: ¿Qué significan las siguientes afirmaciones?
const a;
int const a;
const int * a
int * const a
int const * a const
Los dos primeros tienen el mismo efecto, A es un número entero constante. El tercer significado es que a es un puntero a un número entero constante (es decir, el número entero no se puede modificar, pero el puntero sí). El cuarto significado de A es un puntero constante que apunta a un número entero (es decir, el número entero señalado por el puntero se puede modificar, pero el puntero no se puede modificar). El último significa que a es un puntero constante que apunta a un número entero constante (es decir, el número entero al que apunta el puntero no se puede modificar y el puntero no se puede modificar). Si un candidato puede responder correctamente a estas preguntas, entonces me ha causado una buena impresión. Por cierto, puede preguntar, incluso si no se usa la palabra clave const, es fácil escribir un programa con la función correcta. Entonces, ¿por qué valoro tanto la palabra clave const? También tengo las siguientes razones:
1). La función de la palabra clave const es transmitir información muy útil a las personas que leen tu código. De hecho, declarar un parámetro como constante le dice al usuario el propósito del parámetro. Si pasa mucho tiempo limpiando la basura que dejan los demás, rápidamente aprenderá a apreciar la información adicional. (Por supuesto, los programadores que saben cómo usar const rara vez dejan la basura a otros para que la limpien).
2) El uso de la palabra clave const puede producir un código más compacto al brindarle al optimizador información adicional.
3) El uso razonable de la palabra clave const permite al compilador proteger naturalmente los parámetros que no desean cambiar y evitar que el código los modifique involuntariamente. En resumen, esto reduce la aparición de errores.
Inestable
8. Qué significa la palabra clave volátil y dé tres ejemplos diferentes.
Una variable definida como volátil significa que la variable puede cambiarse accidentalmente, por lo que el compilador no asumirá el valor de la variable. Para ser precisos, el optimizador debe volver a leer cuidadosamente el valor de esta variable cada vez que se utiliza, en lugar de utilizar la copia de seguridad almacenada en un registro. Los siguientes son algunos ejemplos de variables volátiles:
1). Registros de hardware de dispositivos paralelos (como registros de estado).
2) Variables no automáticas a las que se accederá en la rutina del servicio de interrupción.
3). Variables compartidas por múltiples tareas en aplicaciones multiproceso.
Las personas que no puedan responder a esta pregunta no serán contratadas. Creo que esta es la cuestión más básica que distingue a los programadores de C de los programadores de sistemas integrados. Los programadores de sistemas integrados a menudo se ocupan de hardware, interrupciones, RTOS, etc., que requieren variables volátiles. No comprender el contenido volátil es una receta para el desastre.
Suponiendo que el entrevistado respondiera correctamente a esta pregunta (bueno, dudo que ese fuera el caso), profundizaría un poco más para ver si la persona realmente entendió toda la importancia de lo volátil.
1). ¿Los parámetros pueden ser constantes o variables? Explique por qué.
2). ¿Pueden los punteros ser volátiles? Explique por qué.
3). ¿Cuál es el problema con la siguiente función:
int square(volatile int *ptr)
{
return? * ptr * * ptr
}
Aquí están las respuestas:
1).Sí. El registro de estado de sólo lectura es un ejemplo. Es volátil porque puede cambiarse inesperadamente. Es constante porque los programas no deben intentar modificarlo.
2).Sí. Aunque esto no es muy común. Un ejemplo es cuando una subrutina de servicio fija un puntero a un búfer.
3). Hay una broma en este código.
El propósito de este código es devolver el cuadrado del valor señalado por el puntero *ptr, pero como *ptr apunta a un parámetro variado, el compilador generará un código similar al siguiente:
int square (volatile int *ptr )
{
int a, b
a = * ptr
b = * ptr p>
Devuelve a * b;
}
Dado que el valor de *ptr puede cambiar inesperadamente, A y B pueden ser diferentes. Por lo tanto, es posible que este código no devuelva el valor al cuadrado que espera. El código correcto es el siguiente:
Rectángulo (variable int *ptr)
{
int a;
a = *ptr
Devuelve un * a
}
Operación de bits
9. Los sistemas integrados siempre requieren que los usuarios realicen operaciones de bits en variables o registros. operar. Dada una variable entera a, escriba dos fragmentos de código. El primero establece el bit 3 de a y el segundo borra el bit 3 de a. En las dos operaciones anteriores, mantenga los demás bits sin cambios.
Hay tres respuestas básicas a esta pregunta.
1).No sé cómo empezar. Nunca he realizado ningún trabajo en sistemas integrados.
2). Utilizar campos de bits. Los campos de bits son algo que se ha arrojado al callejón sin salida del lenguaje C. Garantiza que su código no sea portátil entre diferentes compiladores y también garantiza que su código no pueda reutilizarse. Recientemente vi un controlador escrito por Infineon para su complejo chip de comunicación, que usa campos de bits. Es completamente inútil para mí porque mi compilador implementa campos de bits de otras maneras. Éticamente: nunca permita que un tipo no integrado se quede en el borde del hardware real.
3). Utilice #definición y máscara de bits para operar. Este es un método muy portátil y debe utilizarse. La mejor solución es la siguiente:
#define bit 3(0x 1 <<3)
Static int a;
void set_bit3(void)
p>{
a | = BIT3
}
void clear_bit3(void)
{
a & amp= ~ BIT3
}
A algunas personas les gusta definir una máscara y algunas constantes de interpretación para establecer y borrar el valor, lo cual es aceptable. Algunos puntos que me gustaría ver: Explicación de constantes, operaciones |= y &=~.
Accede a ubicaciones de memoria fijas.
10. Los sistemas integrados a menudo requieren que los programadores accedan a ubicaciones de memoria específicas. En un proyecto, debe establecer el valor de la variable entera con dirección absoluta 0x67a9 en 0xaa66. Este compilador es un compilador ANSI puro. Escriba código para realizar esta tarea.
Esta pregunta prueba si sabes que es legal convertir un número entero en un puntero para acceder a una dirección absoluta. La forma en que aborda esto varía según su estilo personal. Un código similar típico es el siguiente:
int * ptr
ptr = (int *)0x67a 9;
* ptr = 0x aa 55;
Un enfoque más oscuro es:
*(int * const)(0x67a 9) = 0x aa 55;
Incluso si su gusto se acerca más a la segunda opción, También te recomendaría que utilices la primera opción en tu entrevista.
Interrupciones (interrupciones)
11. Las interrupciones son una parte importante de los sistemas integrados, lo que ha llevado a muchos desarrolladores de compiladores a proporcionar una extensión para permitir que el estándar C admita interrupciones. El hecho representativo es que se genera una nueva palabra clave __interrupt. El siguiente código utiliza la palabra clave __interrupt para definir una subrutina de servicio de interrupción (ISR). Por favor comente sobre este código.
_ _Interrumpir doble área_cómputo(doble radio)
{
Área doble = PI *radio*radio;
printf(" Área = %f ", Área);
Área de retorno;
}
Esta función tiene tantos errores que la gente no sabe por dónde empezar:
1).ISR no puede devolver un valor. Si no entiendes esto, no te contratarán.
2).ISR no puede pasar parámetros. Si no ves esto, tus posibilidades de ser contratado son las mismas que la primera.
3). En muchos procesadores/compiladores, el punto flotante no suele ser reentrante. Algunos procesadores/compiladores requieren apilar registros adicionales, y algunos procesadores/compiladores simplemente no permiten operaciones de punto flotante en ISR. Además, el ISR debe ser breve y eficiente, y no es aconsejable realizar operaciones de punto flotante en el ISR.
4). De acuerdo con el tercer punto, printf() a menudo sufre problemas de reentrada y rendimiento. Si pierdes el tercer o cuarto punto, no te lo pondré demasiado difícil. No hace falta decir que si puede cumplir con los dos últimos puntos, sus perspectivas de empleo serán cada vez más brillantes.
Ejemplo de código
12. ¿Cuál es el resultado del siguiente código y por qué?
void foo(vacío)
{
Unsigned int a = 6
int b =-20;
(a+b>6)Put(">6"):puts("<=6");
}
Esta pregunta prueba si entiendes el Principio de conversión de enteros del lenguaje C. Descubrí que algunos desarrolladores saben muy poco sobre estas cosas. De todos modos, la respuesta a este problema de enteros sin signo es que la salida es ">:6". La razón es que cuando en una expresión están presentes tipos con y sin signo, todos los operandos se convierten automáticamente a tipos sin signo. Entonces, -20 se convierte en un entero positivo grande, por lo que esta expresión se evalúa como mayor que 6. Esto es importante para sistemas integrados donde a menudo se utilizan tipos de datos sin firmar. Si responde mal a esta pregunta, corre el riesgo de no conseguir el trabajo.
13. Evalúe el siguiente fragmento de código:
Unsigned int zero = 0;
Unsigned int compzero = 0xFFFF
/* Zero's complemento de 1*/
El código anterior es incorrecto para procesadores donde el tipo int no es de 16 bits. Debería escribirse así:
Entero sin signo comp cero = ~ 0;
Esta pregunta realmente puede revelar si el candidato comprende la importancia de la longitud de las palabras del procesador. En mi experiencia, los buenos programadores integrados entienden los detalles del hardware y sus limitaciones con mucha precisión, pero los programadores de PC a menudo tratan el hardware como una molestia inevitable.
En esta etapa, el candidato está completamente frustrado o confiado y decidido a ganar. Si es obvio que el candidato no es muy bueno, entonces la prueba termina aquí. Pero si es obvio que al candidato le fue bien, descartaré las siguientes preguntas complementarias, que son más difíciles. Creo que sólo los muy buenos candidatos pueden obtener buenos resultados. Al hacer estas preguntas, espero ver más respuestas del candidato que las respuestas. De todos modos, considérelo como entretenimiento...
Asignación de memoria dinámica (asignación de memoria dinámica)
14 Aunque no es tan común como las computadoras no integradas, los sistemas integrados todavía tienen memoria. asignación del montón El proceso de asignación dinámica de memoria. Entonces, ¿cuáles son los posibles problemas con la asignación de memoria dinámica en sistemas integrados?
Aquí espero que los candidatos mencionen la fragmentación de la memoria, la recolección de desechos, el tiempo de retención variable, etc.
Este tema se trata extensamente en las revistas ESP (principalmente por P.J. Plauger, quien explica mucho más de lo que puedo mencionar aquí), ¡así que vuelve a consultar esas revistas! Después de pedirles a los candidatos que ingresaran una falsa sensación de seguridad, saqué un pequeño programa como este: ¿Cuál es el resultado del siguiente fragmento de código y por qué?
char * ptr
if((ptr =(char *)malloc(0))= = NULL)
puts("Obtener un puntero nulo" );
Otros
puts("Obtener un puntero válido");
Esta es una pregunta interesante. No había pensado en esto hasta hace poco, hasta que un colega mío pasó accidentalmente un valor de 0 a la función malloc y obtuvo un puntero válido. Este es el código anterior. El resultado de este código es "obtuve un puntero válido". Utilicé esto para abrir una discusión sobre un tema de este tipo y ver si el entrevistado pensaba que esto era lo correcto en las bibliotecas de forma rutinaria. Obtener la respuesta correcta es importante, pero el enfoque para resolver el problema y los principios subyacentes de la toma de decisiones son aún más importantes.
Typedef
15.Typedef se utiliza a menudo en lenguaje C para declarar sinónimos de tipos de datos existentes. También puedes hacer cosas similares con preprocesadores. Por ejemplo, considere el siguiente ejemplo:
#define estructura dPS *
estructura typedef s * tPS
La intención en ambos casos anteriores es combinar dPS y tPS Definido como un puntero a una estructura s, ¿qué enfoque es mejor? (Si es así) ¿Por qué?
Ésta es una cuestión muy delicada y cualquiera que la responda bien (por las razones correctas) debería ser felicitado. La respuesta es: typedef es mejor. Considere el siguiente ejemplo:
dPS p1, p2;
tPS p3, P4
La primera extensión es
estructura s *; p1,p2;
El código anterior define p1 como un puntero a una estructura y p2 como la estructura real, que probablemente no sea lo que desea. El segundo ejemplo define correctamente dos punteros p3 y p4.
16. El lenguaje C respalda algunas construcciones impactantes. ¿Es legal la siguiente estructura? Si es así, ¿qué hace?
int a = 5, b = 7, c;
c = a+++b
Esta pregunta será la respuesta perfecta a este examen. final. Lo creas o no, el ejemplo anterior es perfectamente gramatical. La pregunta es ¿cómo lo maneja el compilador? Los compiladores de bajo nivel en realidad discutirán este tema y, de acuerdo con el principio de procesamiento máximo, el compilador debería poder manejar todos los usos legales si es posible. Por lo tanto, el código anterior se procesa como:
c = a+++b;
Entonces este código va seguido de a = 6, b = 7, c = 12+02 .