C Interview Questions 02: Makefile, Scope and Lifetime, Call by Value, & Data Types
Makefile | scope & lifetime | call by value | sizes of data types | memory layout
Code regarding Makefile on Github: https://github.com/yu-cheng-kuo-28/makefile-demo
Continuing from the previous article, we now move on to Makefile, memory layout, scope & lifetime, sizes of data types, & type conversion with demos I created on my VPS (Ubuntu 20.04 LTS x64) on Vultr.
C Interview Questions 01: Pointers
C Interview Questions 03: Bitwise Operations / Sizes of Structs / Volatile
Outline
(0) Setup of Vim
(1) Call By Value vs. Call By Reference
(2) Makefile
(3) More on Makefile
(4) Memory Layout
(5) Scope and Lifetime of Storage Classes
(6) Sizes of Data Types
(7) More on Sizes of Data Types
(8) Type Conversion
(9) References
(0) Setup of Vim
- .vimrc
set cindent
set expandtab " Use spaces for indentation
set tabstop=4 " Number of spaces for a tab stop
set shiftwidth=4 " Number of spaces for auto-indenting
autocmd FileType make set noexpandtab tabstop=4 shiftwidth=4
In Linux systems, place this file in your home directory.
While this article does not require prior knowledge of Vim, you may optionally explore Vim’s functionalities at your discretion.
(1) Call By Value vs. Call By Reference
Q: Compare C & C++ in terms of the forms of function calls.
Ans:
According to C++ Primer, there’re only two main forms of function calls, that is, call by value and call by reference.
- C: call by value (pointers are call by value of address, which belong to call by value)
- C++: call by reference
(2) Makefile
Q: Create a simple Makefile to compile main.c and foo.c, and clean up main.o and foo.o files
Ans:
# Create a simple Makefile to compile main.c and foo.c, and clean up main.o and foo.o files
# Target: main
main: main.o foo.o
gcc main.o foo.o -o main
# Target: main.o
main.o: main.c
gcc main.c -c
# Target: foo.o
foo.o: foo.c
gcc foo.c -c
# Target: clean
clean:
rm -rf main.o foo.o
(3) More on Makefile
- A Makefile is used to control the build process of a project, specifying how to compile and link the program.
Let’s take a look at an example of Makefile with these 6 files.
- [1] Makefile
# Makefile
# This Makefile builds the program myProgram from abc.c, xyz.c, and main.c
# The default target:
all: myProgram
# The main program depends on object files.
myProgram: abc.o xyz.o main.o
gcc -o myProgram abc.o xyz.o main.o
# Each .o file depends on its corresponding .c file.
abc.o: abc.c abc.h
gcc -c abc.c
xyz.o: xyz.c xyz.h
gcc -c xyz.c
main.o: main.c xyz.h
gcc -c main.c
# The clean rule for cleaning up
clean:
rm -f abc.o xyz.o main.o myProgram
- [2] main.c
// main.c
#include "abc.h"
#include "xyz.h"
int main() {
abc_function();
xyz_function();
return 0;
}
- [3] abc.h
// abc.h
#ifndef ABC_H
#define ABC_H
void abc_function();
#endif
- [4] abc.c
// abc.c
#include "abc.h"
#include <stdio.h>
void abc_function() {
printf("Function abc_function called.\\n");
}
- [5] xyz.h
// xyz.h
#ifndef XYZ_H
#define XYZ_H
void xyz_function();
#endif
- [6] xyz.c
// xyz.c
#include "xyz.h"
#include <stdio.h>
void xyz_function() {
printf("Function xyz_function called.\\n");
}
And here’s the output.
root@DemoYuChengKuo:~/makefileDemo# ls
abc.c abc.h main.c Makefile xyz.c xyz.h
root@DemoYuChengKuo:~/makefileDemo# make
gcc -c abc.c
gcc -c xyz.c
gcc -c main.c
gcc -o myProgram abc.o xyz.o main.o
root@DemoYuChengKuo:~/makefileDemo# ls
abc.c abc.h abc.o main.c main.o Makefile myProgram xyz.c xyz.h xyz.o
root@DemoYuChengKuo:~/makefileDemo# ./myProgram
Function abc_function called.
Function xyz_function called.
root@DemoYuChengKuo:~/makefileDemo# ls
abc.c abc.h abc.o main.c main.o Makefile myProgram xyz.c xyz.h xyz.o
root@DemoYuChengKuo:~/makefileDemo# make clean
rm -f abc.o xyz.o main.o myProgram
root@DemoYuChengKuo:~/makefileDemo# ls
abc.c abc.h main.c Makefile xyz.c xyz.h
Below is what I got on my VPS (Ubuntu 20.04 LTS x64) on Vultr:
(4) Memory Layout
Q: Explain the differences of stack & heap in memory layout of C.
(5) Scope and Lifetime of Storage Classes
Q: Compare and explain static & extern variables.
Ans:
(6) Sizes of Data Types
Q: Fill out the "?"s.
size of char = ?? byte(s)
size of unsigned char = ?? byte(s)
size of short = ?? byte(s)
size of unsigned short = ?? byte(s)
size of int = ?? byte(s)
size of unsigned int = ?? byte(s)
size of long = ?? byte(s)
size of unsigned long = ?? byte(s)
size of long long = ?? byte(s)
size of unsigned long long = ?? byte(s)
size of float = ?? byte(s)
size of double = ?? byte(s)
Ans:
For a 64-bit machine,
size of char = 1 byte(s)
size of unsigned char = 1 byte(s)
size of short = 2 byte(s)
size of unsigned short = 2 byte(s)
size of int = 4 byte(s)
size of unsigned int = 4 byte(s)
size of long = 4 byte(s)
size of unsigned long = 4 byte(s)
size of long long = 8 byte(s)
size of unsigned long long = 8 byte(s)
size of float = 4 byte(s)
size of double = 8 byte(s)
The output above came from the code below:
(1) Makefile
sizeData: sizeData.c
gcc -o sizeData sizeData.c
clean:
rm -f sizeData
(2) sizeData.c
#include <stdio.h>
int main() {
// %u : unsigned integer value
// %zu : unsigned integer value to print the value of a size_t, such as the result of the sizeof operator.
printf("size of char = %zu byte(s)\n"
"size of unsigned char = %zu byte(s)\n\n"
"size of short = %zu byte(s)\n"
"size of unsigned short = %zu byte(s)\n\n"
"size of int = %zu byte(s)\n"
"size of unsigned int = %zu byte(s)\n\n"
"size of long = %zu byte(s)\n"
"size of unsigned long = %zu byte(s)\n\n"
"size of long long = %zu byte(s)\n"
"size of unsigned long long = %zu byte(s)\n\n"
"size of float = %zu byte(s)\n"
"size of double = %zu byte(s)\n",
sizeof(char),
sizeof(unsigned char),
sizeof(short),
sizeof(unsigned short),
sizeof(int),
sizeof(unsigned int),
sizeof(long),
sizeof(unsigned long),
sizeof(long long),
sizeof(unsigned long long),
sizeof(float),
sizeof(double));
return 0;
}
Below is what I got on my VPS (Ubuntu 20.04 LTS x64) on Vultr:
(7) More on Sizes of Data Types
Now, let’s dig deeper into it with the following tables.
(8) Type Conversion
- [1] Type Casting (Explicit Conversion): Type casting is when a programmer explicitly converts a value from one type to another. This is done using the casting operator, which is specified in parentheses before the value to be converted.
- [2] Type Conversion (Implicit Conversion): Type conversion can also occur implicitly, which means the compiler automatically converts one type to another when it is necessary and legal to do so.
Let’s observe this by an instance:
(1) Makefile
typeDemo: typeDemo.c
gcc -o typeDemo typeDemo.c
clean:
rm -f typeDemo
(2) typeDemo.c
#include <stdio.h>
int main() {
int integerVar = 10;
int integerVar_2 = 3;
double doubleVarExplicit;
double doubleVarImplicit;
// Explicitly cast an int to a double
doubleVarExplicit = (double)integerVar;
// Implicit conversion from int to double
doubleVarImplicit = integerVar; // No casting operator needed
printf("Integer variable: %d\n", integerVar);
printf("Double variable after explicit casting: %.2f\n", doubleVarExplicit);
printf("Double variable after implicit conversion: %.2f\n\n", doubleVarImplicit);
// printf("%.2f\n", integerVar/integerVar_2); // CE or Get 0.00 since they are all integers
printf("%.2f\n", (float)integerVar/integerVar_2); // Make one of them to float
printf("%.2f\n", integerVar/(float)integerVar_2); // Make one of them to float
return 0;
}
Below is what I got on my VPS (Ubuntu 20.04 LTS x64) on Vultr:
(9) References
- Lippman, S. B., Lajoie, J., & Moo, B. E. (2012). C++ Primer (5th ed.). Addison Wesley.
- 蔡文龍、何嘉益、張志成、張力元、歐志信、陳士傑(2021)。C & C++程式設計經典(第五版)。台北:碁峯資訊。
- 劉邦鋒(2019)。由片語學習C程式設計(第二版)。台北:國立臺灣大學出版中心。
- My interview experience [2023/11/30]
- C/C++ — 常見 C 語言觀念題目總整理(適合考試和面試) [2017]
- Classic C Interview Questions [2016]
- [面試] 聯發科技 MTK (內含考題) [2011]