Did you know? in C language
Some lesser known facts about C language
'sizeof'
is an operator (and not a function as one might think)
- Some valid expressions with
sizeof
operatorsizeof (int)
// int, float, double, char, etc.sizeof variable_name
// without parenthesis a variable is acceptedsizeof (variable_name)
// variable inside parenthesissizeof (expression)
// return the size of the ‘result of the expression’
Many keywords are overloaded in C
- static
- when used with variable, it is visible only in that translation unit (if globally declared in a file) or retains its value from call to call (if declared inside a function)
- when used with function declaration/signature, change its scope (makes the function visible only in this file). - extern
- when applied to a function declaration, change its scope (publicly visible)
- when applied to a variable, indicates its definition exists elsewhere - *
- in mathematical expressions, the multiplication operator
- in a variable declaration, declares an address location pointer variable
- in expression beside pointer variable, dereferencing or indirection - &
- alongside a variable, address of the variable
- in expressions as a binary operator, bitwise AND operator
Some of the operators have the wrong precedence
Namespaces do exist in C
Namespaces do exist in C in a subtle way and their scope is very broad when compared to the C++ namespace scheme.
Different namespaces in C are:
1. label names
2. tags (one namespace for all structs, enums and unions)
3. member names (each struct or union has its own namespace)
4. everything else
Everything in the same namespace should be unique. So the following declaration is legal in C.struct foo { int foo; } foo;
Arrays and Pointers are not the same
Let’s get it straight, the major difference is at the compiler level. So what does that mean? That means as follows:
int a[10];
int *b;
a[1]
and *(b + 1)
are processed differently. And in the generated executable, there is a significant difference in both expressions.
The address of a[1]
is known at the compile-time while the address of *(a + 1)
is not known at run-time. This is how it works — a[1]
is resolved to an address-value and put into code to access the value directly*(b + 1)
is resolved into 1. Access the value at `b`; 2. Increment the value (address) by 1 unit; 3. now access the value at this generated address
Function prototype with empty params can accept arguments!!
[ Easy to forget ]
Reference
For example, the following function prototype will accept any number of arguments in its actual call. The following call to the function is valid and compiler considers as acceptable.
void func () {
printf("hello\n");
}
void func1 (void) {
printf("hello\n");
}
int main() {
func(1, 1, 3); // no issues
func1(1, 1, 1); // wrong
}
No compiler switch can enable detection of this behaviour. To mitigate this, the correct intent for the prototype should be as follows:
void func (void);