Table of Contents
What is an identifier ?
An identifier , is used to denote an object type in C
. An object in C
is a region of memory , used for data storage .
int x ; /* x is an identifier , or the label for an area of storage of type int .*/ struct time{ int hours ; int seconds; };/* time is an identifier , for an aggregate user defined type , struct . time is also known as a tag . The term tag , is also used to refer , to user defined types : enum , union . struct time can be used to define , new variables , of type struct time . variables of types struct time , occupy a region of storage in memory capable of holding two integers .*/ enum color{red , green , blue }/* color is an identifier , for a user defined type , enum . In this , case the user defined type , is an integer . color is also known as a tag . enum color , can be used to define new variables of type enum color , which can take integer values . red , green , blue are integer constants .*/
Object types in c are :
- integer types , such as int , short , enum …
- floating types , such as float , double , long double .
- structures .
- unions .
- arrays .
- pointers .
- atomic types .
An identifier , is also used to denote members of : unions , structs , and enums . So in the previous example , hours
, seconds
, red
, and green
are also identifiers .
An identifier can also be used to denote a function , for example :
int aFunction(void);/* aFunction is an identifier . */
Identifiers can also be used to denote : label names.
#include<stdio.h> void edit(int code){ if(code == 0) goto success ; else goto failure ; success: // success is an identifier for a label printf("sucess\n"); failure: // failure is an identifier for a label printf("failure\n");} int main(void){ edit(0); edit(1);}/* Output : sucess failure failure*/
Finally an identifier can be used to denote : a typedef name , a macro name , and a macro parameter .
typedef float weight ; /* weight is an identifier */ #define SUM(x,y) (x + y) ;/* SUM , x , y are identifiers.*/
The characters , and length of an identifier
An identifier is case sensitive , it can contain the following characters : [A-Za-z0-9_]
. It must start with a non digit character , so it cannot start with digits from 0
, till 9
.
Universal character names , can also be used in identifiers , so a \u
followed by four hex digits , or a \U
followed by 8 hex digits , can be used in an identifier . The hex digits , must form a valid , unicode code number .
Universal character names , can be used on systems , where some characters are not available . The range of universal character names , which are allowed , can be found in annex D.1 of the C standard , as for those which are not allowed at the start of an identifier , they can be found in annex D.2 of the C standard .
/* Example of a valid identifiers*/ int _valid; int int \u1D00num = 1; /* Example of an invalid identifiers */ int 1a = 0 ;
The C standard does not define a limit on the length of an identifier , whereas some implementations might set a limit . As such the C standard impose a limit , on the minimum length , that implementations must support .
The minimum number of characters that must be supported by an implementation , for external linkage identifiers , such as global variables or global functions , is at least 31
characters , as for those with internal linkage , so non global variables or functions , is 63
characters .
Name spaces of identifiers
Identifiers can be in one of these four name spaces :
- The tag of a struct , union and enum , form one namespace .
- Each struct , and union , form a namespace for its members .
- Labels , have their own namespace .
- All other identifiers , belong to the same namespace , and they are called ordinary identifiers .
We cannot have the same identifiers defined , in the same namespace , unless , they belong to different scope .
struct x{int x;}; enum y{x}; int z; int func(int z ); /* The tag x for the struct x , and the tag y for the enum y , belong to the same namespace . Each struct and union , form a namespace for its members . As such int x; belong to the namespace of the struct x . Labels form their own namespace . All others identifiers belong to the same name space . As such , x , z , func , and z , belong to the same namespace , but they might have different scope . Scope is visibility .*/
Scope of an identifier
The scope of an identifier is the visibility of this identifier . There are four scopes , that identifiers can belong to :
The function prototype scope , is for the parameters defined inside each function prototype . It is not necessary to provide an identifier , for parameters defined in a function prototype .
int x ; int sum(int x , int y );/* x , and x belong to the same name space , the ordinary name space , but they have different scopes . In the sum function prototype declaration , we have two parameters , which have the sum function prototype scope , they are : x and y .*/
Labels declared inside functions , have function scope . Each function , has its own function scope .
Block scope , is defined by curly brackets , it starts with {
and end with }
. Function parameters , belong to the block scope , of the function definition .
#include<stdio.h> void dimension(int x , int y ){ for( int i = 0 ; i< 10 ; i++){ printf("%d",i);} printf("\n"); printf("%d,%d\n", x , y);}/* x , y , belong to the block scope , following the parameter list , of the dimension function , and are only visible inside this block scope . i , belong to the block scope , following the for loop clauses , and is only visible inside this block scope.*/ int main(void){ dimension(0,1);}/* Output : 0123456789 0,1*/
File scope , is everything else , so anything which is not defined in a block scope , function scope , or function prototype scope. File scope is the global scope .
int x = 1 ;/* x belong to the file scope .*/
An identifier is visible , from the moment it is declared , till the end of its scope . The end of a file scope , is the translation unit . Nested blocks , hide the visibility of identifiers , defined in the outer block .
#include<stdio.h> int a = -1; void options(int a){ printf("a : %d\n",a); if(a == 0){ int a = 1 ; printf("a : %d\n",a);} printf("a : %d\n",a);} int main(void){ printf("a : %d\n",a); options(0); int z = -1 , t = z; printf("z : %d , t : %d\n", z , t);}/* Output : a : -1 a : 0 a : 1 a : 0 z : -1 , t : -1