No tendría sentido decir que getch y ungetch no pueden verlas. O es un error grave del traductor, o lo estás malinterpretando.
Dado que apenas empiezas, es normal que mucho de esto te sea confuso. La palabra static en C (y C++) es un asunto medio complicado. Por ejemplo, tiene distinto significado según dónde se use. Esto no es una exageración, literalmente, quienes crearon las reglas del lenguaje decidieron reutilizar la palabra static para no aumentar "innecesariamente" el número de palabras reservadas. Eso ha sido motivo de debate prácticamente desde el principio, con muchos programadores considerando que las reglas fueron un error, que se debió haber recurrido a diferentes palabras reservadas para los distintos usos, etc. pero pues esto es lo que hay.
Te doy una explicación muy breve, limitándome a lo relevante para este ejemplo. Ten en cuenta que el asunto es mucho más complejo que la simplificación que estoy haciendo, pero tratar de ser más completo y riguroso resultaría en un texto muy largo y no tiene caso complicar más esto (igual si no lo entiendes del todo, lo puedes guardar como referencia para cuando ya sepas más).
Los dos usos de static que son relevantes ahora son en referencia a la duración de una variable, y a su "visibilidad" (realmente en inglés se le llama linkage).
La duración se refiere a durante cuánto tiempo "existe" una variable. Las variables locales (no static) tienen duración automática, es decir, sólo existen dentro del bloque (por ejemplo, función) donde fueron definidos. Las variables globales tienen duración estática: existen durante toda la ejecución del programa.
En cuanto a la visibilidad, por defecto, las variables globales tienen visibilidad externa: pueden ser accedidas desde otros archivos fuente. Lo único que se necesita es que desde esos otros archivos el programador indique al compilador que va a usar estas variables. La forma correcta es, desde esos otros archivos, declararlas como extern. Por ejemplo, siguiendo el ejemplo de getch.c, si yo incluyera ese archivo en un proyecto mío, y agregara otro archivo (digamos, externo.c) y pusiera esta declaración:
Esto le avisa al compilador que voy a usar una variable entera llamada bufp, que está definida en algún otro lado (en este caso, en getch.c). Fíjate que el hecho de que yo haya puesto la palabra extern indica que yo sé que esa variable está definida en otro archivo, y que de forma intencionada quiero acceder a ella. Pero resulta que la palabra extern no es del todo indispensable. Si yo la omitiera, y simplemente la declarara así en mi archivo:
Creyendo que estoy definiendo una variable únicamente para uso mío, estaría equivocado. En realidad estaría compartiendo la misma variable que getch, justo como si la hubiera declarado como extern. Porque aunque no es lo más correcto, muchos compiladores permiten omitir el especificador extern (siempre que se cumplan ciertas condiciones). En este caso, mi programa compilaría perfectamente y sin errores, pero, de forma totalmente accidental e indeseada, estaría compartiendo una variable con el otro archivo
. Ojo, esto no funciona en todos los compiladores (y los compiladores de C++ son más estrictos), pero es muy probable que el compilador de C que uses lo permita sin marcar error.
Al declarar una variable global como static, especificas que tiene visibilidad (o alcance) interna, y no se puede acceder desde fuera. Con eso evitas accesos, intencionales o no, desde el exterior. Muchos piensan que se debió usar una palabra reservada nueva (por ejemplo "intern") para este fin, ya que en realidad no estamos declarando la variable como estática; desde el momento en que es variable global, ya es estática, y nosotros simplemente estamos cambiando su visibilidad. La palabra static no tiene realmente sentido en este contexto, pero en fin...