¿El scope en C está relacionado solo con el tiempo de comstackción, ya que sabemos que podemos acceder a cualquier memoria en tiempo de ejecución?

Estaba tratando de entender el significado exacto del scope en C. Lo que pude entender es que el scope se limita solo al tiempo de comstackción. Por ejemplo, en caso de que acceda a la variable local desde alguna otra función. Esto dará lugar a un error de tiempo de comstackción. Por otro lado, el siguiente progtwig funciona bien. Esto significa que la C tiene un modelo de memoria plana y se puede acceder a todo en el tiempo de ejecución. Los libros C asocian el scope con la vida útil y la visibilidad variable, lo encontré bastante confuso. Creo que todos estos términos tienen sentido solo para el tiempo de comstackción. ¿Alguien por favor puede arrojar luz sobre él?

#include "stdio.h" int *ptr; int func(void) { /** abc is a local variable **/ int abc = 132; ptr = &abc; return 0; } int func1(void) { /** although scope of abc is over still I can change the value in the address of abc **/ *ptr = 200; printf("the value of abc=%d\r\n",*ptr); } int main(void) { func(); func1(); return 0; } 

Resultados: el valor de abc = 200

En las palabras más simples, ¿qué se entiende por scope? ¿Aparece en la imagen en tiempo de ejecución o de comstackción? Como podemos ver, podemos acceder a cualquier cosa en el tiempo de ejecución. Pero, si no seguimos las reglas, obtendremos el error de comstackción. Por ejemplo, la referencia de variable local en otra función. El comstackdor lanzará un error que dice “variable no definida …”.

¿Puedo decir lo siguiente sobre las variables?

 1) Scope attribute comes under compile time. 2) Lifetime attribute comes under run-time. 3) Visibility attribute comes under compile-time 

Sí, el modelo de memoria de C le permite acceder a cualquier cosa fácilmente, por lo que puede hacer cosas como las anteriores y ver resultados “interesantes”.

Sin embargo, lo que hizo aquí se especifica como un comportamiento no definido (UB) por el estándar C. Eso significa que literalmente cualquier cosa puede pasar; Eso podría ser lo que esperas, o puede que no.

Tenga en cuenta que no accedió a “la variable local” porque en el momento en que hace que la func acceso ya haya regresado, la vida útil de sus variables locales ya ha expirado. Lo que accedió fue una región de memoria que “simplemente sucedió” para tener un valor interesante. Si llama func1 desde adentro func entonces el comportamiento estaría bien definido.

Algunas notas más:

El scope es definitivamente un concepto de solo comstackción; el scope de un nombre (variable, identificador, etc.) es el subconjunto del código del progtwig donde el comstackdor reconoce ese nombre.

Esto es muy diferente al tiempo de vida de las variables, que es independiente del scope en el caso general, y la combinación de ambas es un error común. De hecho, la vida útil y el scope de las variables locales están entrelazados, pero eso no es cierto en todo.

Mientras que en teoría es “solo UB”, en la práctica está pidiendo fallar realmente. La ubicación de abc es (en cada implementación que conozco) en algún lugar de la stack. Ya que dejó el bloque inicial y luego ingresó a otro bloque, es muy probable que algo más ocupe esa ubicación de la memoria. Que vas a sobreescribir.

¿Qué se entiende por scope?

El scope de una variable es la parte del texto en el que se puede hacer referencia a la variable. Una variable local tiene un ámbito de bloque : es visible desde su punto de statement hasta el final del cuerpo de la función envolvente.
No tiene nada que ver con la vida útil de una variable . Es la duración del almacenamiento la que indica el tiempo de vida de una variable.

¿Aparece en la imagen en tiempo de ejecución o de comstackción?

Entra en la imagen en tiempo de comstackción y tiempo de enlace. Cuando el progtwig intentará acceder a una variable local fuera de su bloque, el comstackdor le dará un error sobre esa variable no declarada (que es local a su bloque).
Este ejemplo lo explicará mejor:

 #include  void userlocal(void); int main() { int a= 2; printf("local a in outer scope of main is %d\n",a); userlocal(); printf("local a in scope of userlocal is %d\n",b); // This will give error at compile time return 0; } void userlocal(void) { int b = 20; printf("local a in scope of userlocal is %d\n",b); } 

Salida:

 [Error] 'b' undeclared (first use in this function) 

¿Puedo decir lo siguiente sobre las variables?

Sí puedes decir.

En lo que se refiere al ámbito, es más fácil pensar que C se comstack en una serie de manipulaciones de registros y memorias, estructuras como bloques, bucles for, sentencias if, estructuras, etc., no tienen ningún significado más allá de la comstackción. abstracciones para permitirte como progtwigdor mantener tu cordura.

En lo que respecta al ejemplo y la memoria, aquí está mi bash de explicarlo .

Como todo el mundo está diciendo, está usando ciertas implementaciones específicas de comstackdores de una acción no definida, según el estándar. Para entender cómo funciona esto, puede pensar que el progtwig que está escribiendo tiene dos memorias, el montón y la stack. Como ejemplo char *foo = malloc(50); asigna memoria en el montón y char foo[] = "Foo" asigna en la stack. La stack es la memoria que recuerda lo que está haciendo y contiene una larga lista de marcos de stack, cada llamada de función agrega un marco y cada retorno muestra un marco. El montón es el otro tipo de memoria.

Para ilustrar esto tenemos este progtwig:

 int *ptr; int func() { int abc = 123; ptr = &abc; return 0; } int func1() { int def; printf("func1() :: *abc=%i\n", *ptr); def = 200; return 0; } int main() { func(); printf("main() :: *ptr=%i\n", *ptr); func1(); printf("main() :: *ptr=%i\n", *ptr); } 

Y lo siguiente ocurrirá en la stack ( - es memoria no definida / no utilizada, > a la izquierda es donde se está ejecutando su progtwig actualmente, X es datos):

 |-----| |-----| |-----| 

Cuando entramos en main() , empuja el marco de stack a la stack:

  |-----| |-----| >|XXXXX| <- This is where all memory needed to execute main() is. 

Luego llama a func() que, en la memoria necesaria para ejecutar, contiene el entero 123 .

  |-----| >|XX123| <- This is the stack frame for func() |XXXXX| <- Still the stack frame for main() 

func() establece el puntero global *ptr a la dirección del entero en la stack. Esto significa que cuando func() devuelve (y la memoria no se borra ya que sería una pérdida de ciclos de CPU) el valor permanece

  |-----| |--123| >|XXXXX| <- main() 

y aún puede ser referenciado por *ptr hasta que llame a la siguiente función

  |-----| >|XXXXX| <- This is the stack frame for func1() |XXXXX| 

Ahora *ptr parecerá tener un valor aleatorio ... pero aún puedes acceder a la posición de la memoria y cambiarla. (Si func() y func1() definen cada uno solo un entero local en su scope, es muy probable que *ptr apunte a ese entero en func1() también)

Prima

No he probado el progtwig pero supongo que se imprimirá algo como esto:

 main() :: *ptr=123 func1() :: *ptr= main() :: *ptr= 

Tienes razón en que C tiene un modelo de memoria plana. Y permite acceder a cualquier región de memoria. Aquí ptr es un puntero global a un int . Así que apunta a una dirección donde se puede almacenar y recuperar un entero. Esto conducirá a un undefined behaviour en diferentes tipos de escenarios.

El scope es una propiedad de tiempo de comstackción y se trata cuando la referencia a una variable es válida o cuando es visible, que es diferente de la storage duration o la vida útil de un objeto que indica cuándo es válido acceder a la memoria asociada con la variable.

En este caso, abc tiene una duración de almacenamiento automático, lo que significa que su duración se extiende para el bloque en el que se encuentra, que en este caso es la función func y el bash de acceder a la memoria asociada con abc fuera de ese bloque es un comportamiento indefinido , puede parecer que Trabajo pero los resultados no pueden ser confiados.

Del borrador C99, sección 6.2.4 Duración de almacenamiento de objetos, el párrafo trata sobre las distintas duraciones de almacenamiento: static y automatic . En explica que una vida útil de variables static es la ejecución completa del progtwig y en el párrafo 5 dice:

Para un objeto de este tipo que no tiene un tipo de matriz de longitud variable, su tiempo de vida se extiende desde la entrada al bloque con el que está asociado hasta que la ejecución de ese bloque finaliza de alguna manera. [..]

Entonces, una variable de vida automática es el bloque en el que se encuentra y el párrafo 2 dice:

La vida útil de un objeto es la parte de la ejecución del progtwig durante la cual se garantiza que el almacenamiento está reservado para él. Un objeto existe, tiene una dirección constante, 25) y retiene su último valor almacenado durante toda su vida útil.26) Si se hace referencia a un objeto fuera de su vida útil, el comportamiento no está definido. El valor de un puntero se vuelve indeterminado cuando el objeto al que apunta llega al final de su vida útil.

Por lo tanto, referirse a un objeto fuera de su tiempo de vida garantizado es un comportamiento indefinido.

Es indefinido y no debes confiar en el valor. Con pequeños cambios en su código (MSVC 2013) hay una sorpresa.

 int func1() { /** although scope of abc is over still I can change the value in the address of abc **/ printf("the value of abc=%d\r\n", *ptr); *ptr = 200; printf("the value of abc=%d\r\n", *ptr); return 0; } int main() { func(); printf("the value of abc=%d\r\n", *ptr); func1(); } 

la salida está en mi computadora

el valor de abc = 132
el valor de abc = 1519668
el valor de abc = 200