C
C is a general-purpose, procedural computer programming language
Created by Dennis MacAlistair Ritchie (his site) and Kenneth Lane Thompson
C is a strongly-typed, weakly checked language
"C is not a big language, and it is not well served by a big book." - Brian W. Kernighan, Dennis M. Ritchie
Hello, World
This is the canonical example of a C program:
c// hello.c #include <stdio.h> int main(void) { printf("Hello, World!"); }
Compile the program using
gcc
orclang
:bashgcc -o hello hello.c # or clang -o hello hello.c
Run the program:
bash./hello
NOTE
If you get an error like : permission denied: ./hello
in Linux/Unix, then run chmod +x hello
to make the file executable
Syntax of C
The syntax of C is based on the syntax of the B language, which was developed by Ken Thompson in 1970 at Bell Labs. B was a simplified version of the BCPL language developed by Martin Richards in 1966. BCPL was a typeless language, but B introduced types
- C is a case-sensitive language (
Play
,play
, andPLAY
are different) - C programs are written in a text editor and saved with the
.c
extension - C programs are compiled using a compiler like
gcc
orclang
or any other C compiler
Comments
Comments will be completely ignored by the compiler:
/* hello world program
* multi-line comments
*/
// single line comment
Reserved Words
Reserved words in C cannot be used as identifiers (variable names, function names, etc.)
- There are 32 keywords in C
auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while
Structure of the Code
In C, main()
function should only have variable declarations and function calls
Example:
/* comment
*
* Converts distances from miles to kilometres.
*/
#include <stdio.h> // preprocessor directive: printf, scanf definitions
// ^ static header file
#define KMS_PER_MILE 1.609 // preprocessor directive: conversion constant
// ^ constant macro
// ^ constant identifier
int // return type
main(void) // function name
{
double miles, // distance in miles
// ^ data type
kms; // equivalent distance in kilometres
// ^ variable identifier
// Get the distance in miles.
printf("Enter the distance in miles> ");
scanf("%lf", &miles);
// ^ standard identifier
// Convert the distance to kilometers.
kms = KMS_PER_MILE * miles;
// ^ ^ operators
// Display the distance in kilometers.
printf("That equals %f kilometers.\n", kms);
return (0); // return statement
// ^ reserved word
}
Compiling and Linking
C/C++ programs consist of source files and headers. Source files and headers are usually text files, but need not be
Much of the text in C/C++ source and header files represents declarations
- The declarations establish the existence of entities such as functions, namespaces, objects, templates, types, and values
C/C++ has no specific rules about which declarations must go into source files and which must go into headers
For a function, we typically:
declare
it in a header, and...define
it in a corresponding source file
However, for a function that's inline,
constexpr
, orconsteval
, then:define
it in a header file
Steps:
Source code (.c) file
|
v
.---------------.
| Pre-processor | <-------- Header files
.---------------.
|
| <-------- expanded code
|
v
.---------------.
| Compiler |
.---------------.
|
.--------------.
|
v
Assembly code (.s) file
|
.--------------.
|
v
.---------------.
| Assembler |
.---------------.
|
.--------------.
|
v
Object code (.o) file
|
.--------------.
|
v
.---------------.
| Linker | <-------- Libraries
.---------------.
|
v
Executable file
Pre-processor:
- Flag:
-E
to Pre-process output tostdout
- Strip out comments
- Anything that starts with pound sign, or "octothorpe", (
#
) is something the preprocessor operates on #include
: This C Preprocessor tells compiler to pull the contents of another file and insert it into the code right there#define
: This C Preprocessor tells compiler to replace all instances of a certain string with another string- Replaces all the macros with the actual code
<stdio.h>
: It is known as a header file (they don't get compiled?)- TODO: Check if source files can be generated like
hello.i
- Flag:
Compiler: Compiler produce assembly code, machine code, or whatever anything based on options
Flag:
-S
to generate assembly code.s
file is an assembly file or Intermediate Representation (IR) codeSolution Configuration: Rules and configurations to build the project
Solution Platforms: Platform that is being targeted
Only C/C++ files are complied not Header files
Every C/C++ file is complied individually into a respective Object file
Liker: Stitches all these Object file into an executable file
Compiler compiles a C++ file if it only contains function declaration without and definition and is used inside that file.
C++ files are called Translation Units (Files have no meaning to C++ Compiler)
Assembler: Translate assembly code to object file
- Flag:
-c
to compile only .o
file is an object file- It is not an executable file
- It is the code in machine language (binary) that the computer can understand
- Flag:
Linker: Combines object files into an executable file
- Flag:
-o
to specify output file name - Linking all the source files together, that is all the other object codes in the project.
- Linking function calls with their definitions. The linker knows where to look for the function definitions in the static libraries or dynamic libraries
- Flag:
Running
gcc
orclang
without any flags will compile and link the code and produce an executable file (a.out
)Use the Compiler flag
-save-temps
to save temporary files (like.i
,.s
,.o
)Some compilers like
clang
produce an intermediate representation (IR) ("pseudo-assembly") code before the assembly code (file extension:.ll
)- To generate the IR code, use the flag
-emit-llvm
likeclang -emit-llvm -S hello.c
- To generate the IR code, use the flag
Example Program
Let's say we are writing a add program, which is split into two files:
main.c
: Contains themain
function and uses methods fromadd.c
add.c
: Contains theadd
functionCreate
add.c
and write theadd
function:c// add.c int add(int a, int b) { return a + b; }
Compile the add file to object file:
bashgcc -c add.c # output: add.o
Now, create
main.c
and use the add function in the main file:c// main.c #include <stdio.h> int main() { printf("Sum: %d\n", add(10, 20)); return 0; }
Compile the main file to object file:
bashgcc -c main.c # output: # ./main.c:6:25: error: implicit declaration of function ‘add’
The compiler is not able to find the
add
function because it is in a different file, so we need let the compiler know about theadd
function by defining the function prototype in the main file:c// main.c #include <stdio.h> int add(int a, int b); int main() { printf("Sum: %d\n", add(10, 20)); return 0; }
Compile the main file again:
bashgcc -c main.c # output: main.o
Create the executable file:
bashgcc -o main main.o # output: # main.c:(.text+0x1a): undefined reference to `add'
The linker is not able to find the
add
function, so we need to link theadd.o
file with themain.o
file:bashgcc -o main main.o add.o # output: main
We have successfully compiled and linked the program. Now, run the executable file:
bash./main # output: Sum: 30
In the above example we added the function prototype in the main file which helps the compiler to know about the add
function. But if need to use the add
function in multiple files, then we have to write the function prototype in all the files. To avoid this, we can create a header file and include it in all the files:
Create a header file
add.h
and write the function prototype:c// add.h int add(int a, int b);
Include the header file in the main file, or any other file where you want to use the
add
function:c// main.c #include <stdio.h> #include "add.h" int main() { printf("Sum: %d\n", add(10, 20)); return 0; }
We can represent the dependencies between the files in a diagram called a dependency graph
Runtime Bounds Checking
Checks for buffer overflows and underflows at runtime
gcc -o test test.c -fsanitize=address -fsanitize=bounds
Compiler Flags
Compiler flags are used to specify the behaviour of the compiler and the output that is generated
-std=c99
: Use the C99 standard, or-std=c2x
for the C2x standard (latest that the compiler supports)gnu17
: default in GCC and Clang
-o
: Output file name-E
: Pre-process output tostdout
-S
: Generate assembly code-c
: Generate object file-l
: Link with library (like-l m
formath.h
library)-g
: Debugging information-v
: Display the programs invoked by the compiler-Wall
: Enable all warnings-Werror
: Treat warnings as errors-Wextra
: Enable extra warnings-fsanitize=address
: Address Sanitizer-Wdocumentation
: Warn about issues in documentation comments-pedantic
: Issue all warnings demanded by strict ISO C and ISO C++-O0
: No optimization (default)-O1
: Optimize-O2
: More optimization-O3
: Even more optimization-O4
: All optimization-march=native
: Optimize for the current machine-ffast-math
: Assume no NaNs or Infs--save-temps
: Save temporary files (like.i
,.s
,.o
)
Headers and Namespaces
Pre-processor statements:
#pragma once
: Include the file only once in the compilation process- Header guards:
#ifndef
,#define
,#endif
c// sum.h #pragma once int sum(int a, int b); // or for older compilers #ifndef SUM_H #define SUM_H int sum(int a, int b); #endif
Namespace:
cpp// sum.h #pragma once namespace customSum { int sum(int a, int b); } // sum.cpp namespace customSum { int sum(int a, int b) { return a + b; } } // Main file #include "sum.h" int main() { cout << customSum::sum(10, 20); return 0; }
"Include hell" is a term used to describe a situation where a project has a large number of dependencies, and each dependency has its own dependencies, and so on. This can lead to a situation where a single source file can include hundreds of header files
Dynamic type using auto
Maps are like JavaScript objects.
Unity Build
Unity build is a technique where you include all your source files into a single file and compile that file. This can speed up the compilation process because the compiler can see all the code at once and optimize it better
It is also known as a "single compilation unit" or "jumbo build"
// unity.c
#include "file1.c"
#include "file2.c"
#include "file3.c"
Address Sanitizer (ASAN)
ASAN is a runtime memory error detector for C/C++ programs. It finds:
- Use after free (dangling pointer dereference)
- Heap buffer overflow
- Stack buffer overflow
- Global buffer overflow
- Use after return
- Use after scope
- Initialization order bugs
- Memory leaks
Memory
The main memory can divided into:
Heap:
Stack:
Code Section:
Example:
int main()
{
int A[5];
int B[5]={2,4,6,8,10};
int i;
for(i=0;i<5;i++)
{
printf("%d", B[i]);
}
}
// ARRAYS A AND B WILL APPEAR IN THE STACK AFTER DECLARATION.
Data Types
A type defines a set of possible values and a set of operations that can be performed on those values
An object is some memory that holds a value of a given type
A value is a set of bits in memory interpreted according to a type
A variable is a named identifier that refers to a value in memory
A declaration is a statement that introduces an identifier (name) and describes its type, be it a type or a function (describing its signature: return type, name, and parameters)
- The compiler uses the declaration to determine how much memory to allocate for the identifier, how to interpret the bits stored there, and to check that the operations performed on the identifier are valid
- It can be done multiple times
- It can be done without initialization
- It does not allocate memory
This thing exists somewhere
cint a; // declaration: int is the type, a is the identifier char c; // declaration: char is the type, c is the identifier int add(int a, int b); // declaration: int is the return type, // add is the identifier, int a, int b are the parameters
A definition actually instantiates/implements the identifier, the compiler asks memory manager to set aside memory for that value or function
- It can be done only once
- The function definition includes the function body
This thing exists here; make memory for it
cint a = 10; // definition: int is the type, a is the identifier, 10 is the value char c = 'A'; // definition: char is the type, c is the identifier, 'A' is the value int add(int a, int b) // definition: int is the return type, { // add is the identifier, int a, int b are the parameters return a + b; // function body }
An initialization is a declaration with an initial value (definition + definition)
- It can be done only once
- It allocates memory and assigns a value
Here is the initial value for this thing
cint a = 10; // initialization: int is the type, a is the identifier, 10 is the value char c = 'A'; // initialization: char is the type, c is the identifier, 'A' is the value
A constant is a value that cannot be changed
- It is a literal value
- It is a compile-time value
cconst int a = 10; // constant: int is the type, a is the identifier, 10 is the value #define PI 3.14 // constant: PI is the identifier, 3.14 is the value
A literal is a value that appears directly in the code
- It is a compile-time value
cint a = 10; // 10 is a literal char c = 'A'; // 'A' is a literal
If a variable is declared but not initialized, then it will contain a garbage value (whatever was in that memory location before)
- Compilers can initialize variables to zero, but it is not guaranteed
The size of the data types is compiler dependent especially before C99 standard, but after C99 standard new data types are introduced which have fixed sizes (like int32_t
, int64_t
, etc.)
NOTE
If something is declared but not defined, then the linker doesn't know what to link references to and complains about a missing symbols. If you define something more than once, then the linker doesn't know which of the definitions to link references to and complains about duplicated symbols
Character
Character data types are used to store characters (letters, digits, symbols)
char
keyword is used to declare a character variable- It is 1 byte in size
- A
'
(single quote) is used to represent an ASCII character (like'A'
,'B'
,'1'
,'2'
,'!'
,'@'
, etc.) - Numbers from 0 to 127 can also be stored in a
char
variable
String Representation
In C, a string is represented as an array of characters terminated by a null
character (\0
ASCII value 0
)
- A string is stored in a contiguous memory location
- C dose not have a built-in string data type
char name[6] = {'J', 'o', 'h', 'n', '\0'};
char name[] = "John";
There are two ways to represent a string in C:
Using a character array:
- A string is represented as an array of characters terminated by a
null
character (\0
ASCII value0
)
cchar name[6] = {'J', 'o', 'h', 'n', '\0'}; char name[] = "John";
- A string is represented as an array of characters terminated by a
Using a character pointer:
- A string is stored in a contiguous memory location
cchar *name = "John";
The difference between a character array and a character pointer is that a character array is a fixed-size memory location, whereas a character pointer is a variable-size memory location
Integer
Integer data types are used to store whole numbers (positive or negative)
Data Type | Range |
---|---|
short | -32,768 .. 32,767 |
unsigned short | 0 .. 65,535 |
int | -2,147,483,648 .. 2,147,483,647 |
unsigned | 0 .. 4,294,967,295 |
long | -2,147,483,648 .. 2,147,483,647 |
unsigned long | 0 .. 4,294,967,295 |
New data types introduced in C99 standard:
Better data types for fixed-width integers using
stdint.h
:- Like size of
int
is not fixed, it depends on the compiler/target (it should be at least 16 bits)
C89 C99 Windows Linux signed char
int8_t
long int
int32_t
int64_t
long long
int64_t
unsigned short
uint16_t
char
Any size int8_t
,int16_t
,int32_t
,int64_t
,uint8_t
,uint16_t
,uint32_t
,uint64_t
uintptr_t
ensures that the variable is large enough to hold a pointer- Constants like
INT32_MAX
- Like size of
Floating Point Numbers
Floating-point data types are used to store real numbers (positive or negative)
float
keyword is used to declare a single-precision floating-point variabledouble
keyword is used to declare a double-precision floating-point variable
Data Type | Significat Digits | Range (approx.) |
---|---|---|
float | 6 | ±3.4E-38 .. ±3.4E+38 |
double | 15 | ±1.7E-308 .. ±1.7E+308 |
long double | 19 | ±3.4E-4932 .. ±1.1E+4932 |
Numerical Precision
When working with floating-point numbers, the operations are not always exact and can have some loss of accuracy or round-off errors (or representational error) due to the way floating-point numbers are stored in memory (binary representation)
- Precision: The number of digits that can be stored in a floating-point number
- Accuracy: The closeness of the measured value to the true value
#include <stdio.h>
int main()
{
float a = 1.0;
float b = 10.0;
float c = a / b;
printf("%.10f\n", c); // 0.1000000015
return 0;
}
In the above example, the result of a / b
is 0.1000000015
instead of 0.1
due to the loss of accuracy in floating-point numbers (round-off error)
When a very large number is added to a very small number, the small number is lost due to the limited precision of floating-point numbers. It is called catastrophic cancellation (or cancelation error)
- To avoid this, use a tolerance value when comparing floating-point numbers (like
1e-6
) instead of exact equality
- To avoid this, use a tolerance value when comparing floating-point numbers (like
When two very small numbers are multiplied, the result may be too small to be represented accurately. It will be represented as
0
, which is called arithmetic underflowWhen two very large numbers are multiplied, the result may be too large to be represented accurately. It will be represented as
infinity
, which is called arithmetic overflowWhen a number is divided by
0
, the result isINFINITY
(present inmath.h
) (printed asinf
), which is called division by zero (or singularity) error
Void
The void
data type is used to specify that a function does not return a value or a pointer that does not point to any data type (like void *
)
- It is used to specify that a function does not take any parameters
void printMessage()
{
printf("Hello, World!");
}
// use `void` to specify that the function does not take any parameters
// it is recommended to use `void` in the parameter list
void printMessageWithVoid(void)
{
printf("Hello, World!");
}
int main()
{
void *ptr;
printMessage(25); // warning: Too many arguments in call to 'print_hello' [warn_call_wrong_number_of_arguments]
printMessageWithVoid(25); // error: Too many arguments to function call, expected 0, have 1 [typecheck_call_too_many_args]
return 0;
}
Arrays
Definition: Contiguous area of memory consisting of equal-size elements
Declared with size inside square brackets
[]
It can be declared without size, but in this case it must be initialized with items. The size of the array will be equal to the number of items
If number of items are less than the declared size of an array, the rest of the places will be filled with
0
If an array is declared and never initialized then it will contain garbage values
Example:
#include <stdio.h>
int main()
{
int A[5] = {1, 2, 3, 4, 5};
int B[] = {1, 2, 3}; // SIZE 3
int C[5] = {1, 2, 3}; // {1,2,3,0,0}
int D[2]; // {3213, 234324}
for (int i = 0; i < 5; i++)
{
printf("%d\n", A[i]);
}
printf("Completed");
return 0;
}
Struct (Structure)
Definition: It's a physically grouped list of dissimilar data items under one name in a block of memory, allowing the different data items to be accessed via a single pointer. It's used for defining user-defined data types, apart from the primitive data types
- Group of related data items
struct
is the keyword used to define a structure.
(dot operator) is used to access the members of the structure- Its size will the sum of sizes consumed by all of its elements
- Structure Padding is used to allocate memory for a structure
Example: Define a struct
called Rectangle
// DEFINITION
struct Rectangle
{
int length;
int breadth;
} r1, r2; // GLOBAL STRUCT VARIABLES
int main()
{
// DECLARATION (MEMORY IS ALLOCATED)
struct Rectangle r;
struct Rectangle r1={10,5};
// INITIALISATION
r.length=25;
printf("Area of the Rectangle is %d", r.length * r.breadth);
}
struct Card
{
int face;
int shape;
int color;
};
int main()
{
struct Card deck[52]={{1,0,0}, {0,0,1}, .... };
deck[0].face=2;
}
struct
do not have member functions
Directives
Directives are commands to the compiler that start with a #
symbol and are processed before the actual compilation of the program
#include
: Includes a file in the program (like#include <stdio.h>
for a standard library or#include "file.h"
for a user-defined file)#define
: Defines a macro (a name that represents a value)- It notifies the preprocessor to replace all instances of the identifier by the value
Standard Functions and Libraries
printf
printf
is a standard library function in C that prints formatted output to the standard output stream (stdout)
It is defined in the
stdio.h
header fileIt returns the number of characters printed (excluding the
null
byte)It is a variadic function, which means it can take a variable number of arguments
The format string is a string that contains format specifiers, Format specifiers start with a
%
symbol, The format specifiers are replaced by the values of the argumentsThe format specifiers are:
%d
: Integer%f
: Float%c
: Character%s
: String%p
: Pointer%x
: Hexadecimal%zu
:sizeof
value
The format string can contain escape sequences:
\n
(newline)\t
(tab)\\
(backslash)\"
(double quote)\'
(single quote)
The format string can contain width specifiers:
%5d
(5 characters wide)%10.2f
(10 characters wide with 2 decimal places)
The format string can contain flags:
+
(always show sign)-
(left-justify)0
(pad with zeros)#
(alternate form)- space (space if positive)
The format string can contain length modifiers:
h
(short)l
(long)ll
(long long)j
(intmax_t)z
(size_t)t
(ptrdiff_t)L
(long double)
The format string can contain conversion specifiers:
d
(decimal)i
(integer)o
(octal)u
(unsigned decimal)x
(hexadecimal)X
(uppercase hexadecimal)f
(float)e
(scientific notation)E
(scientific notation)g
(shortest representation)G
(shortest representation)a
(hexadecimal float)A
(hexadecimal float)c
(character)s
(string)p
(pointer)n
(number of characters written so far)%
(percent sign)
#include <stdio.h>
int main()
{
int a = 10;
float b = 20.5;
char c = 'A';
char s[] = "Hello, World!";
void *p = &a;
printf("Integer: %d\n", a);
printf("Float: %f\n", b);
printf("Character: %c\n", c);
printf("String: %s\n", s);
printf("Pointer: %p\n", p);
printf("Hexadecimal: %x\n", a);
return 0;
}
Placeholder | Type | Function Use |
---|---|---|
%c | char | printf /scanf |
%d | int | printf /scanf |
%f | double | printf |
%lf | double | scanf |
Versions
1972: First release
1978: K&R C
1989: C89 (ANSI C)
- Most of the C code written today is based on the ANSI C standard
- Almost every C compiler available today is ANSI C compliant
- Every platform/target
- Can be compiled with a C++ compiler (with no or minimal changes)
1999: C99
- Added several new features to the C language
- Standardized
//
comments - Local variable declarations:
c// C89 int main(void) { // All variables must be declared at the beginning of the block int i; for (i = 0; i < 10; i++) { printf("%d", i); } // i is still in scope here } // C99 int main(void) { for (int i = 0; i < 10; i++) { printf("%d", i); } // i is not in scope here }
- Initializing structure members:
ctypedef struct { int id; int age; char* name; } User; // C89 // Order of initialization must match the order of the structure members // You can't skip any member User rick = { 557, 30, "Rick" }; // C99: Designated initializers // You can initialize the structure members in any order // You can skip any member User rick = { .name = "Rick", .id = 557, .age = 30 };
Better data types for fixed-width integers using
stdint.h
, likeint32_t
,int64_t
, etc.Compound literals:
- A compound literal is an unnamed object that is created on the fly
- It is a way to create an object of a structure or array type without giving it a name
- It is useful when you need to pass a structure
c// C89 Point point = {1, 2}; draw_point(point); // C99 draw_point((Point){1, 2});
2011: C11
2018: C17
2024: C23
Code Style
Naming Conventions
Code Formatting
Using clang-format
, you can format your code:
clang-format -style=llvm -dump-config > .clang-format
Different styles of writing C code:
// Allman
while (x == y)
{
func1();
func2();
}
// Kernighan & Ritchie
while (x == y) {
func1();
func2();
}
// GNU
while (x == y)
{
func1 ();
func2 ();
}
// Whitesmiths
while (x == y)
{
func1();
func2();
}
// Horstmann
while (x == y)
{
func1();
func2();
}
// Haskell style
while (x == y)
{ func1()
; func2()
;
}
// Ratliff style
while (x == y) {
func1();
func2();
}
// Lisp style
while (x == y)
{ func1();
func2(); }
Memory Leaks
#include <stdlib.h>
#include <string.h>
Floating Point Numbers
IEEE 754: Floating point number specification
- It is a compression algorithm
Bits | Precision |
---|---|
16 bit | Half Precision |
32 bit | Single Precision |
64 bit | Double Precision |
128 bit | Quadruple Precision |
256 bit | Octuple Precision |
Floating point numbers in 16 Bit System:
- The floating point number's binary representation is split into 3-parts:
Sign (1 Bit):
- Number is Positive or Negative
Exponent (5 Bits):
- Represents a range
Exponent ( n
)Power Range ( 2^n
)Numerical Range 0 [0, 1] [1, 2] 1 [1, 2] [2, 4] 2 [2, 3] [4, 8] 3 [3, 4] [8, 16] 4 [4, 5] [16, 32] Mantissa (10 Bits):
(Number - lower bound) / (upper bound - lower bound)
For 64 Bit system:
- Sign (1 Bit)
- Exponent (11 Bits)
- Mantissa (52 Bits)
Formula that represents a floating point number:
N = (-1)^sign * 1.mantissa * 2^(exponent - 15)
According to IEEE 754 spec:
-0
ifsign=1
,exponent=00000
, andmantissa=0000000000
INFINITY
ifexponent=11111
andmantissa=0000000000
-INFINITY
ifsign=1
NaN
ifexponent=11111
andmantissa=someValue
- There are man
NaN
- There are man
2^0
: de-normalized number
Example:
The number: 25.1 (decimal) is stored as:
- Sign: 0 (Positive)
- Exponent: 131 (1000 0011)
- Mantissa: 4771021 (1001 0001 1001 1001 1001 101)
Value actually stored in float: 25.1000003814697265625
Error due to conversion: 0.0000003814697265625
Binary Representation: 0100 0001 1100 1000 1100 1100 1100 1101
Hexadecimal Representation: 41C8CCCD
References:
References
Documentation: If you're on a Unix system then run man 3 printf
C Reference Manual, that came with 6th Edition Unix (May 1975)
The C Programming Language, Second Edition (og)
- TODO: Read "The C Programming Language", Second Edition - 1988
International Obfuscated C Code Contest: a wonderful competition wherein the entrants attempt to write the most unreadable C code possible, with often surprising results
c// one of the entries in the 2001 E((ck?main((z?(stat(M,&t)?P+=a+'{'?0:3: execv(M,k),a=G,i=P,y=G&255, sprintf(Q,y/'@'-3?A(*L(V(%d+%d)+%d,0)