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
