-
Notifications
You must be signed in to change notification settings - Fork 160
/
function.c
455 lines (341 loc) · 11.9 KB
/
function.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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
/*# function
A function is basically a branch, but in which you have to:
- know where to jump back to after return
- pass arguments
- get back a return value
*/
#include "common.h"
void func_int(int i) {}
void func_float(float f) {}
void func_double(double d) {}
/* Struct arguments and return */
struct struct_func_struct {
int i;
int j;
};
struct struct_func_struct struct_func() {
return (struct struct_func_struct){ 0, 1 };
}
/*
Declaration vs definition
*/
/* Two decls on the same line, with same return type: */
int decl_1(), decl_2();
int decl_1(){ return 1; }
int decl_2(){ return 2; }
void decl_def();
void decl_def();
void decl_def() {}
/* ERROR redefine */
/*void decl_def() {}*/
int factorial2funcs1(int);
int factorial2funcs0(int n){
if (n != 1) {
return n*factorial2funcs1(n - 1);
}
return 1;
}
int factorial2funcs1(int n){
if (n != 1) {
return n*factorial2funcs0(n - 1);
}
return 1;
}
#if __STDC_VERSION__ <= 199901L
/*default_return_type() { return 1; }*/
#endif
int proto_empty_definition() {
return 1;
}
/* ERROR cannot define on same line */
/*int decl_3(){return 3;}, decl_4(){return 4;};*/
/* Can declare a function that returns int and a int var with the same `int`. */
/* Very confusing! */
int decl_and_initialize_func(), decl_and_initialize;
int decl_and_initialize_func(){ return 0; }
int k_and_r(a, p)
int a;
char *p;
{
return 0;
}
/*
# overload
There is no function overloading in C to avoid name mangling:
C ABI simplicity is one of it's greatest strengths:
http://stackoverflow.com/questions/8773992/c11-type-generic-expressions-why-not-just-add-function-overloading
C11 introduces generics, which allow for a similar, albeit more limited effect.
*/
void overload(int n) {}
/* ERRORS: */
/*void overload(float n) {}*/
/*void overload(int n, int o) {}*/
void func_int_ptr (int *i) {}
void func_int_arr (int i[]) {}
/*
function struct args
how to deal with passing structs to/from functions
*/
struct FuncReturn { int i; };
struct FuncReturn structReturn(struct FuncReturn sIn) {
struct FuncReturn s_out;
s_out.i = sIn.i + 1;
return s_out;
}
/* # return const from func */
/* -Wignored-qualifiers */
const int const_int_func() {
return 0;
}
const int* const_int_ptr_func_int_ptr(int *ip) {
(*ip)++;
return ip;
}
const struct struct_func_struct const_struct_func() {
return (struct struct_func_struct){ 0, 1 };
}
int main(void) {
{
func_int(1.1);
func_float(1);
}
/* Two decls on the same line. */
{
assert(decl_1() == 1);
assert(decl_2() == 2);
}
/* # return */
{
/* Return value is not an lval, so one cannot get its address */
{
int *ip;
/* ERROR */
/*ip = &int_func_int(1);*/
}
/*
# return struct from function.
Behaviour defined by the standards.
Assembly implementation is not specified by ANSI C,
but common techiques used in cdecl like conventions:
- put struct into several registers
- automatically add a hidden argument to functions that return structs,
allocated data on caller and pass a pointer to the struct,
and let the callee modify that pointer to return it.
Sample: definition
struct struct_func_struct struct_func() {
struct struct_func_struct s = { 0, 1 };
return s;
}
gets converted to:
void struct_func(struct struct_func_struct* sp) {
struct struct_func_struct s = { 0, 1 };
*sp = s;
}
And calls:
s = struct_func();
Get converted to:
struct struct_func_struct temp;
struct_func(&temp);
s = temp;
or simply:
struct_func(&s);
In C it is not possible to detect which convertion was made by the compiler.
In C++ however, constructors and destructors allow to differenciate between the two above cases,
and RVO specifies that both are valid options that the compiler may take, and that the actual
results are unpredictable.
*/
{
struct struct_func_struct s;
s = struct_func();
assert(s.i == 0);
assert(s.j == 1);
}
}
/*
# Declaration vs definition
http://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration
Declaration says some information about type, definition specifies it completely.
Every definition is also a declaration.
*/
{
/*
# extern
Variable declaration without definition.
Needs extern, or else it is a definition.
But there is one more step left: initialization.
*/
{
int i;
{
extern int i;
/* ERROR: redeclaration */
/* TODO why? In particular, why does it work if outside of a function? */
/* i = 0; */
/*
TODO why? Possible outside function.
http://stackoverflow.com/questions/17090354/why-does-initializing-of-an-extern-variable-locally-inside-a-function-give-an-er
*/
{
/*extern int i = 0;*/
}
}
}
/* Declaration and definition. */
{
int i;
/* Separate initialization. */
i = 0;
assert(i == 0);
}
/*
Variable declaration, definition and initialization in one statment.
*/
{
int i = 0;
assert(i == 0);
}
/* struct declaration */
{
}
/* Function declaration vs definitions. */
{
/* Function declaration. extern semantics by default. */
void f();
/*
# Local functions
Declaration can be done inside other functions.
Definitions not.
Functions definition inside functions exist only as extensions
in certain compilers such as gcc if ANSI is not enforced.
*/
{
/* ERROR: no definition inside another function: */
/*void func(){}*/
/* The following as defined outside main. */
decl_def();
}
/*
Like for structs, one major application of forward declarations
is to break definition dependency loops.
*/
{
assert(factorial2funcs0(4) == 24);
assert(factorial2funcs1(4) == 24);
}
/*
In C89, some functions can be used without any declaration as long as they are defined in another file.
They are called implicit functions.
They are not allowed in C89.
But you can use functions which have a declaration that is not a prototype (i.e. without argument checking).
*/
}
/*
Declarations can be done any number of times.
Definitions only once per scope (block or static in files).
*/
{
{
extern int i;
extern int i;
struct s;
struct s;
void f();
void f();
}
{
int i;
/* ERROR: redeclaration of i */
/* TODO why is the message redeclaration instead of redefinition? */
/*int i;*/
struct s { int i; };
/* ERROR: redefinition of s */
/*struct s { int i; };*/
}
}
/* Cannot redeclare a symbols as one of another type. */
{
struct i;
/* ERROR i redeclared as nother type */
/*void i();*/
}
/*
# Identifier list
# Parameter list
TODO
- http://stackoverflow.com/questions/18820751/identifier-list-vs-parameter-type-list-in-c
*/
{
/*
# Prototype vs declaration
http://stackoverflow.com/questions/5481579/whats-the-difference-between-function-prototype-and-declaration
- Prototype is a declaration that specifies the arguments.
Only a single prototype can exist.
- a declaration can not be a prototype if it does not have any arguments.
The arguments are left unspecified.
- to specify a prototype that takes no arguments, use `f(void)`
In C++ the insanity is reduced, and every declaration is a prototype,
so `f()` is the same as `f(void)`.
Save yourself some headache, and never write declarations that are not prototypes.
TODO why would someone want to use a declaration that is not a prototype?
*/
{
/* Declaration that is not a prototype. */
void proto_decl();
/* Prototype. */
void proto_decl(int);
/* OK, same prototype as above. */
void proto_decl(int i);
/* ERROR: conflicting type for */
/*void proto_decl(float);*/
/* A definition without arguments however already implies `(void)`. */
/* ERROR */
/*int proto_empty_definition(int);*/
assert(proto_empty_definition() == 1);
/*
# float on a prototype after a declaration
You can't use `float`, `char`, etc.: only `int`, `double`
on prototypes that follow declarations!
http://stackoverflow.com/questions/5481579/whats-the-difference-between-function-prototype-and-declaration
*/
{
void proto_decl_float();
/* ERROR: An argument that has default promotion can't match*/
/*void proto_decl_float(float);*/
void proto_decl_double();
void proto_decl_double(double);
}
}
/* But not with different return types. */
/* ERROR conflicting types for `f` */
/*int f();*/
}
}
/*
# Implicit int
# Default return type
http://stackoverflow.com/questions/12373538/warning-return-type-defaults-to-int-wreturn-type
In C89, if not specified, the return type defaulted to `int`.
Appears to have been made illegal in C99.
`gnu99` allows it by default but gerenrates warnings, `-Wno-return-type` to turn off.
*/
{
#if __STDC_VERSION__ <= 199901L
/* WARN: type default to int in declaration of. */
/*static s;*/
/*assert(default_return_type() == 1);*/
#endif
}
/*
# K&R function declaration
This form of function declaration, while standard,
is almost completely obsolete and forgotten today.
It is however still ANSI C.
There seems to be only one case in which it may allow for something
that ANSI C declarations don't: <http://locklessinc.com/articles/obscurec/>
*/
{
char c = 0;
assert(k_and_r(1, &c) == 0);
}
return EXIT_SUCCESS;
}