hw4_notes.txt Huan Chen, 11/21/2016 ============================================== Common mistakes in your hw4 after grading: - Miss proper assertions in Getters/Setters/Create/DeleteImage functions - Wrong order of free() statements in DeleteImage() - Miss setting NULL to R, G, B pointers for image in DeleteImage(IMAGE *image) - Fail to handle memory free when I read "EH.ppm" multiple times then exit in PhotoLab - Warnings or errors arise when "make", or missing required executables in target "all", even uncompilable - Messy dependences in makefile (some list all header files for every target in case missing something... Or no dependences specified at all) - "#ifdef DEBUG" is not properly handled in Test.c, FileIO.c, PhotoLab.c, missing the corresponding messages in the output when running PhotoLabTest - Improper include statements in source file and header file (either duplicate or not used at all) ============================================== FAQs: 1. Why do we need assert() for all the DIP functions and the Create/DeleteImage/Getters/Setters functions? - If the expression in assert() is false (assertion fails, which it should not), your program crashes right away (abort() is called), then you know where the error is. A prompt message can also be added to the assert expression. For example: assert(image->R && " image->R should not be NULL"); assert(SaveImage(fname, image) == 0 && "Save image should not fail."); 2. Why do we set variables to NULL after free? - In short, to prevent dangling pointer errors, if assertion before free() fails (free NULL pointer), then it indicates your handling of memory free is wrong. Crashing immediately is better than having unknown segmentation fault and tracking back step by step, setting breakpoints in gdb. http://stackoverflow.com/questions/1025589/setting-variable-to-null-after-free 3. "static const" vs "#define"? static const int DIFF = 5; or #define DIFF 5? - static const is type-safe and respects scope. For gcc, static const are stored in the text segment. It makes debugging easier, since "#define" is replaced by the preprocessor. However, it cannot be used as a dimension for arrays at global scope. For example: const int HEIGHT = 480; int myArray[HEIGHT]; // error: variably modified 'myArray' at file scope # define SIZE 5 int array[SIZE]; // it is OK void Aging(unsigned char R[WIDTH][HEIGHT]); // it is OK int main() {...} http://stackoverflow.com/questions/1674032/static-const-vs-define-vs-enum 4. Where to put the include statements, header or source? - Only put includes in a header file if the header itself needs them, for example, DeleteImage() uses free(), then include in the source file; if your function returns size_t, include in the header http://stackoverflow.com/questions/3943352/where-to-put-include-statements-header-or-source 5. Why cannot I go into every line of my code in gdb to print variable values (gdb complaining "No symbol table is loaded")? - Add the "-g" option in CFLAGS to generate source debug info. 6. Why are the images in my website not updated when I run PhotoLabTest? - Try with different web browsers. Check timestamps of the image files in your public_html folder. 7. It is tedious to input multiple menu item numbers in testing PhotoLab (input 1 then EH to load image, then apply negative filter by inputing 3 and 2 to save it as "negative" then exit every time. Is there any way to save typing? - Yes, store the input options in a file, when running your PhotoLab, read from the input file $ ./PhotoLab < input_file # what you have in input_file is: "1 EH 3 2 negative 18 " (suppose input 18 to exit) Or typing this command is still too tedious? Add it to your makefile: ##### Makefile helper targets ##### p: ./PhotoLab < input_file v: valgrind --leak-check=full ./PhotoLabTest # file names of all the output images imgs = negative hflip colorfilter vmirror edge zoom posterize\ overlay crop smallresize bigresize rotate circle # diff command to verify jpg images diff_img = diff ~/public_html/$(img).jpg ~eecs22/public_html/$(img).jpg; # diff all jpg images, if all succeed, no output diff_all: @-$(foreach img, $(imgs), $(diff_img)) ################################## Then "make p", "make v", "make diff_all" can be shorter. 8. How to write elegant make clean commands in our makefile? - It may be nasty to list dozens of ppm images generated after each execution, "rm -f *.ppm" is not OK, as we have to keep the necessary images (EH.ppm and balloon.ppm). Thus the following command can help: ######## Makefile clean ########## # in case there is file named "clean" in the directory causing "make clean" failed .PHONY: clean clean: rm -f *.o *.a `find . -name "*.ppm" ! -name "EH.ppm" ! -name "balloon.ppm"` ################################## 9. Why do GetPixelR(const IMAGE *image...), SaveImage(const char *fname, const IMAGE *image") use the const keyword? - It means read-only. It protects you from overriding the content. In addition, "static" outside of a function marks that the variable is visible to that c file only; if inside, the static variable exists before and after the function ends. 10. I met "Empty JPEG image (DNL not supported)", ? - Check if you have set height/width fields in the image structure correctly in CreateImage(int W, int H).