Did you know? in C language

Some lesser known facts about C language

Ujjwal Kumar
3 min readJul 13, 2020

'sizeof' is an operator (and not a function as one might think)

  1. Some valid expressions with sizeof operator
    sizeof (int) // int, float, double, char, etc.
    sizeof variable_name // without parenthesis a variable is accepted
    sizeof (variable_name) // variable inside parenthesis
    sizeof (expression) // return the size of the ‘result of the expression’
source: https://www.tutorialspoint.com/sizeof-operator-in-c

Many keywords are overloaded in C

  1. 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).
  2. extern
    -
    when applied to a function declaration, change its scope (publicly visible)
    - when applied to a variable, indicates its definition exists elsewhere
  3. *
    -
    in mathematical expressions, the multiplication operator
    - in a variable declaration, declares an address location pointer variable
    - in expression beside pointer variable, dereferencing or indirection
  4. &
    -
    alongside a variable, address of the variable
    - in expressions as a binary operator, bitwise AND operator

Some of the operators have the wrong precedence

source: Expert C Programming (pdf) —

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);

--

--