2.3 FAQ
Is there a quick and easy way to compile all the .c files, generate executable and run the executable?
I understand using a makefile is the recommended method compile a set of .c files. But during coding, I would like to know whether there is a easy and quick way to compile all .c files, generate the executable and run the code at once? Otherwise, I will have to compile each .c file seperate to .o files and then link them together to create the executable and then run it (provided that I still haven’t got my makefile done)
We always recommend you to make the make file since it efficiently handles the compilation process (it only compile the files which are modified). But lets say, you just want to compile a set of .c files as fast as you can to test some sample codes you have written. Then see below:
gcc -Wall -ansi -pedantic *.c -o prog && ./prog/* In linux, you can combine two commands using && */
gcc -Wall -ansi -pedantic *.c -c && gcc *.o -o prog && ./prog
Do we have bool data type or bool literals in C?
C does not have a boolean literal (True
, False
) or boolean type (bool
). Hence, 0
or NULL is interpreted as False, while any non-zero
value is interpreted as True.
Note: NULL is a #define
for (void*) 0
in the compiler dependant header (stddef.h
)
Usually, we #define
0 to be FALSE and 1 to be TRUE as below:
#define FALSE 0#define TRUE 1/* or */#define FALSE 0#define TRUE !FALSE /* !FALSE => !0 => 1 */
The reason why we usually don’t #define
any random non-zero value to be TRUE
is because, when negation !
operator is used on 0
it returns 1
and vice-versa, thereby maintaining the mathematical property of boolean values TRUE == !FALSE
The following examples demonstrate how C interpret boolean values with integer literals:
#include <stdio.h>
/*********************************************************/// RECOMMENDED WAY IN UCP (TRUE must be 1, FALSE must be 0 or !1 which is 0)#define TRUE 1#define FALSE !TRUE/**********************************************************/
int main(){ /* Follwing examples are purely for your knowledge. Refer to the top of this file for the recommended way to define TRUE and FALSE */
/*********************************************************************************************************************************/ /* NOT TODO: Do not do the following to interpret true and false in C. These examples are purely for the understanding of the concept /********************************************************************************************************************************/
/* C does not have boolean datatype or boolean literals (True, False) */ /* Any non-zero used at a place where a condition is expected, will be treated as true in C */ if (1000) { printf("Non-zero value in the place of the condition will be interpretted as true\n"); }
if (0) /* The value 0 or NULL will be interpreted as false */ {
} else { printf("Zero or NULL in the place of the condition will be interpretted as false\n"); }
/* Logical operator ! (not) following a non-zero value, will result in 0 which is then be interpreted as false */
if (!1000) { } else { printf("!<any non-zero value> => 0\n"); }
/* Logical operator ! (not) following a zero value or NULL, will result in 1 which is then be interpreted as true */
if (!0) /* or (!NULL) */ { printf("!<zero or NULL> => 1\n"); } else {
}
/* Checkout the following printf to verify the concepts above */
printf("Boolean TRUE, FALSE: %d, %d\n", TRUE, FALSE); printf("Interpreted true: %d, %d, %d\n", 10, (!(!10)), !NULL); printf("Interpreted false: %d, %ld\n", !10, (long int)NULL);
return 0;}
Can I use MACRO to replace anything?
Yes, you can since macro simply works as find and replace statements. Expanding a macro means, find the occurrences of a macro in the code, replace it with the statement defined for the macro replacing the variables if there are any.
In UCP, it is NOT RECOMMENDED to use macros as you wish! violating the coding standards and affecting the readability of the code. Please use macro ONLY for those short functions with a return value.
A bad example:
#include <stdio.h>
/* ************************************************************************************** *//* NOT TODO: Never use #define in the following way in UCP! *//* These examples are purely for your understanding of the concept */
#define CHECK if /* <- this is the syntax if */
/* following macro expands to a block of code! */#define CHECK_GREATER_100(X) if (X > 100) { printf(">100\n"); } else { printf("<=100\n"); }/* ************************************************************************************** */
int main(){ int num = 150; CHECK_GREATER_100(50)
CHECK (num > 200) { printf(">200\n"); } else { printf("<=200\n"); }
return 0;}
“Makefile:2: * missing separator. Stop”
I keep getting this error when trying to run my makefile. I have used a single TAB on the line after the target file. Changed the ~/.vimrc settings back to standard to see if that would work but still nothing.
Note: This issue happened to a student who used VIM text editor. The most likely reasoning is because the .vimrc (VIM configuration file) does not put an exception for a makefile. Please make sure you have the following command at the end of the .vimrc file:
autocmd FileType make setlocal noexpandtab
Explanation: Makefile needs to use a single TAB space (not 2 or more) for indentation. If the text editor automatically converts any TAB key as multiple space keys, the makefile will not work.
If you use VScode, you can specify that you are writing a makefile when you start a new file. In that case, VScode will automatically use the correct setting for it.
Do we have bool data type or bool literals in C?
C does not have a boolean literal (True, False) or boolean type (bool). Hence, 0 or NULL is interpreted as False, while any non-zero value is interpreted as True.
Note: NULL is a #define for (void*) 0 in the compiler dependant header (stddef.h) Usually, we #define 0 to be FALSE and 1 to be TRUE as below:
#define FALSE 0#define TRUE 1/* or */#define FALSE 0#define TRUE !FALSE /* !FALSE => !0 => 1 */
The reason why we usually don’t #define any random non-zero value to be TRUE is because, when negation ! operator is used on 0 it returns 1 and vice-versa, thereby maintaining the mathematical property of boolean values TRUE == !FALSE The following examples demonstrate how C interpret boolean values with integer literals:
#include <stdio.h>#define TRUE 1#define FALSE !TRUE
int main(){ /* Following examples are purely for your knowledge. Refer to the top of this file for the recommended way to define TRUE and FALSE */
/* NOT TODO: Do not do the following to interpret true and false in C. These examples are purely for the understanding of the concept */
/* C does not have boolean datatype or boolean literals (True, False) */ /* Any non-zero used at a place where a condition is expected, will be treated as true in C */ if (1000) { printf("Non-zero value in the place of the condition will be interpreted as true\n"); }
if (0) /* The value 0 or NULL will be interpreted as false */ {
} else { printf("Zero or NULL in the place of the condition will be interpreted as false\n"); }
/* Logical operator ! (not) following a non-zero value, will result in 0 which is then be interpreted as false */ if (!1000) { } else { printf("!(any non-zero value) => 0\n"); }
/* Logical operator ! (not) following a zero value or NULL, will result in 1 which is then be interpreted as true */ if (!0) /* or (!NULL) */ { printf("!(zero or NULL) => 1\n"); } else {
}
/* Checkout the following printf to verify the concepts above */ printf("Boolean TRUE, FALSE: %d, %d\n", TRUE, FALSE); printf("Interpreted true: %d, %d, %d\n", 10, (!(!10)), !NULL); printf("Interpreted false: %d, %ld\n", !10, (long int)NULL);
return 0;}
Can I pass an integer to a function that expects a char type parameter or vice-versa?
Yes, you can. But remember char has only 8 bits (platform dependant). Therefore you can only store numbers from (-128) to 127 (
char ch;ch = 'A'; /* All good. 'A' is a char literal */ch = 65; /* All good. 65 is a integer literal */ch = "A"; /* ERROR: "A" is a string literal */
Furthermore, since computers cannot understand characters ‘A’, ‘B’, etc, but numbers (in binary) every character on the keyboard corresponds to a special code called “ASCII code” (or Unicode - the extended version of ASCII). Therefore if you assign a char literal to an integer variable, it means you are assigning the corresponding ASCII value of it. Please refer to the ASCII code table here.
int num = 'A'; /* num will be 65 */char ch = 'A'; /* ch will be 65 */
printf("%d", num); /* prints 65 */printf("%d", ch); /* prints 65 */printf("%c", num); /* prints 'A' */printf("%c", ch); /* prints 'A' */
/* char simply means an allocation of 8 bits (platform dependant)whereas int simply means an allocation of 32 bits (platform dependant) */
Basically, invoking functions with char type parameters by passing an integer literal or vice versa follow the same concepts explained above.
#include <stdio.h>void fCh(char ch){ printf("%d", ch); /* prints the numerical value of ch */ printf("%c", ch); /* prints the character corresponds to the value of ch using ASCII conversion table */}void fInt(int num){ printf("%d", num); /* prints the numerical value of num */ printf("%c", num); /* prints the character corresponds to num in relation to the ASCII table */}
int main(){ fCh('A'); fCh(65);
fInt('A'); fInt(65);
return 0;}