-
Notifications
You must be signed in to change notification settings - Fork 160
/
identifier.c
306 lines (234 loc) · 8.24 KB
/
identifier.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#include "common.h"
int main(void) {
/*
# Identifiers
C99 6.2.1.1 "Scope of identifiers".
Identifiers are names either for:
- variables
- functions
- structs
- struct members
- enums
- unions
- macros
- labels (for goto)
Most identifiers are use defined, but C99 has one that is predefined: `__func__`.
*/
{
/* TODO examples of each. */
}
/*
# Scope of identifiers
C99 6.2.1.3-4 "Scope of identifiers".
*/
{
/*
The following scopes exist:
- file scope: global stuff outside any function
- function scope: only for labels. They are not constrained by non-function blocks like braces {}.
- block scope: surrounding braces, either of functions, if, or alone
*/
{
/* TODO */
}
/*
You may define variables in that scope with the same names as external ones,
but if you do so the external ones will become completely invisible
*/
{
int i = 0;
{
assert(i == 0);
/*
From now on, it is impossible to access the outer `i`
from the inner scope.
*/
int i = 1;
assert(i == 1);
}
assert(i == 0);
}
}
/*
# Linkage of identifiers
Three types:
- external: marked as external, with no previous non-external declaration
- internal: file scope or static
- none
*/
/*
# Storage duration of objects
# Lifetime of objects
C99 6.2.4 "Storage duration of objects"
There are 3 types:
- `static`: initilized only once, and live for the entire program. Like static local variables.
- `automatic`: local variables, live until the end of blocks: functions or `{}`.
- `allocated`: `malloc`. Lives until you `free` it.
*/
{
/*
# Dangling pointer from block scope
Undefined behavior: the lifetime of `i` ends because of block C99 6.2.4 p.5.
http://stackoverflow.com/questions/2759371/in-c-do-braces-act-as-a-stack-frame
*/
{
int *ip;
{
int i = 1;
ip = &i;
}
#ifdef UNDEFINED_BEHAVIOUR
if (*ip != 1)
printf("after lifetime: %d\n", *ip);
#endif
}
/*
Undefined behaviour, because the rhs `i` is already the uninitilized inner `i`.
*/
{
int i = 1;
{
int i = i;
/* Same as: */
/*int i;*/
/*i = i;*/
#ifdef UNDEFINED_BEHAVIOUR
printf("i = i scope: %d\n", i);
#endif
}
}
}
/*
# Name space of identifiers
C99 6.2.3 "Name space of identifiers"
Not like the C++ concept.
C has the following identifiers in different namespaces:
- tags of: enums, structs, and union
- labels (of goto)
- members of structs
- the rest: called *ordinary identifiers*: variable, function names
A single identifier can be used many times in a single scope
if it belongs to different namespaces.
Each namespace can be differentiated by the syntax of the language.
In C++, tags are put in the same namespace as variables.
*/
{
/* tag */
struct s {
/* member of struct */
int s;
};
/* Odinary */
int s = 0;
/* Label. */
s:
s = 0;
/* ERROR: conflicting types for. */
/* Ordinary already defined. */
/*float s;*/
/* ERROR. */
/* A struct is also an ordinary identifier. */
/*struct s s;*/
}
/*
Names of identifiers
*/
{
/*
C99 6.4.2 "Lexical Elements > Identifiers"
Allowed identifiers follow the regex: `_[a-Z0-9_]*`
Furthermore, user-defined identifiers should not be the same as:
- keywords
- reserved identifiers
- predefined identifiers
There exist identifier extensions, e.g. GCC allows `$` in identifiers.
*/
{
/* ERROR name cannot start with digit, or C thinks it is an integer literal. */
/*int 0a;*/
}
/*
# Keywords
C99 6.4.2
C99 6.4.2.1 p.4 says:
> When preprocessing tokens are converted to tokens during translation phase 7, if a
preprocessing token could be converted to either a keyword or an identifier, it is converted
to a keyword.
So it is impossible to have an identifier that is the same as a keyword.
Full list:
_Alignas auto extern short
_Alignof break float signed
_Atomic case for sizeof
_Bool char goto static
_Complex const if struct
_Generic continue inline switch
_Imaginary default int typedef
_Noreturn do long union
_Static_assert double register unsigned
_Thread_local else restrict void
enum return volatile
while
*/
/*
# Reserved identifiers for future use
C99 7.3.1 specifies that:
> All identifiers that begin with an underscore and either an uppercase letter
or another underscore are always reserved for any use.
> All identifiers that begin with an underscore are always reserved
for use as identifiers with file scope in both the ordinary and tag name spaces.
Those reservations exist so that the languge may be extended later by the standard.
The following keywords that conflict with reserved identifiers were already introduced:
- introduced in C99:
- `_Bool`
- `_Complex`
- `_Imaginary`
- introduced in C11:
- `_Alignas`
- `_Alignof`
- `_Atomic`
- `_Generic`
- `_Noreturn`
- `_Static_assert`
- `_Thread_local`
so the tendency of the standard is to use `_Upper_case` for new conflicts.
For convience, C99 also defines simpler macros to some new identifiers and adds them to headers, e.g.:
- `_Complex` and `complex` from `complex.h`
- `_Noreturn` and `noreturn` from `stdnoreturn.h`
This allows includers to override the macro with `#undef complex` if necessary.
POSIX adds many further per header reserved names which it would be wise to follow even on ANSI C:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html section "The Name Space".
*/
{
/* May break any in future versions of the standard. */
int _Not_yet_a_keyword;
int __not_yet_a_keyword;
/* Fine because not file scope but rather block scope. */
int _not_yet_a_keyword;
}
/*
Standard seems to say nothing of this edge case,
since `_` is not followed by any letter TODO confirm
Even though it is quite cryptic, it does get some usage as `gettext` call in GNU projects,
which inspired Django internationalization.
The Underscore Javascript library is another notable usage.
*/
{
int _ = 1;
assert(_ == 1);
}
}
#if __STDC_VERSION__ >= 199901L
/*
# Predefined identifiers
There is only one in C99: `__func__`.
# __func__
If inside a function, the name of that function.
This is not a macro, since the preprocessor cannot know
the current function name, because the preprocessor does not parse.
*/
{
assert(strcmp(__func__, "main") == 0);
}
#endif
return EXIT_SUCCESS;
}