Context\ I have been learning C as a hobby since autum 2025 because I am intrigued by computers. I have mainly been using Bro Code’s tutorial and PDF The C Programming Language (Second Edition), although I’m too much of a beginner to understand all of the latter material. There’s not really much more to it. I don’t really have any concrete goals with learning C, but I thought it could be a good first step into the world of programming and for now, I just really enjoy coding. In the future, I’d like to learn assembly language and then finally (?) program some CPU.

Background\ When I realized how I can use for loops to go through strings and how I can then manipulate certain portions of said string, I realized that I can play around with it to allow a user to modify (here, “trim”) any given text. Good fun!

In this particular case, I focused on practicing separating the program into as specific and small functions as possible.

Questions\

  1. Should I or could I call the next function from within the previously called function, as opposed to listing them all in main() as I have done below? My guess is that listing them all in main() gives the reader a better overview of the flow, as opposed to having to look into each separate function to find out what’s connecting to what?

  2. I believe that the only variable that really needs to be global is the “input”, since so many functions need to be able to access it. What are the pros and cons of using local variables where possible?

CODE
#include <stdio.h>  
#include <string.h>  

//Function declarations  
void promptchoice_main(void);  
void promptchoice_main_again(void);  
void promptinput(void);  
void promptchoice_trim(void);  
void executechoice(char choice_trim);  
void trimnumbers(void);  
void trimwhitespace(void);  
void trimletters(void);  
void trimspecial(void);  
void specifyspecial(void);  
void printresult(char input[]);  

//Global variables  
char choice_main = 0x00;  
char choice_trim = 0x00;  
char choice_detail = 0x00;  
char choice_special = 0x00;  
char input[1000] = "";  
char previous_input[1000] = "";  

//Remove specific numbers, letters, punctuation or whitespace characters from input.  
int main() {  
	printf("\nWelcome! This program trims text by removing unwanted characters.\n");  
	while (1) {  
		if (strlen(previous_input) == 0) { // Check for previously trimmed text in memory.  
			promptchoice_main();  
			if (choice_main == 'E') { break; }  
			if (choice_main == 'T') {  
				promptinput();  
				promptchoice_trim();  
				executechoice(choice_trim);  
				printresult(input);  
			}  
		}  
		else {  
			promptchoice_main_again();  
			if (choice_main == 'E') { break; }  
			if (choice_main == 'T') {  
				promptinput();  
				promptchoice_trim();  
				executechoice(choice_trim);  
				printresult(input);  
			}  
			else if (choice_main == 'P') {  
				sprintf(input, "%s", previous_input);  
				printf("\nYou are trimming previously trimmed text: %s\n", input);  
				promptchoice_trim();  
				executechoice(choice_trim);  
				printresult(input);  
			}  
		}  
	}  
	printf("\nGoodbye!\n");  
	return 0;  
}  

//Function definitions  
void promptchoice_main(void) {  
	while (1) {  
		printf("\nPress T and ENTER to trim text or E and ENTER to exit: ");  
		scanf("%c", &choice_main);  
		while (getchar() != '\n') {}  
		if (choice_main == 'T' || choice_main == 'E') { break; }  
		else { printf("\nInvalid input!\n"); }  
	}  
	return;  
}  

void promptchoice_main_again(void) {  
	while (1) {  
	printf("\nPress T and ENTER to trim new text, P and ENTER to trim previously trimmed text or E and ENTER to exit: ");  
	scanf("%c", &choice_main);  
	while (getchar() != '\n') {}  
		if (choice_main == 'T' || choice_main == 'P' || choice_main == 'E') { break; }  
		else { printf("\nInvalid input!\n"); }  
	}  
	return;  
}  

void promptinput(void) {  
	printf("\nEnter the text that you would like to trim and press ENTER: ");  
	fgets(input, sizeof input, stdin);  
	input[strlen(input) - 1] = '\0';  
	return;  
}  

void promptchoice_trim(void) {  
	while (1) {  
		printf("\nWhat would you like to trim?\n1) Numbers (1, 2, 3...)\n2) Whitespace (space, tab or newline) \n3) Letters (A,B,C... a,b,c...)\n4) Special characters (!,?, . , ...)\nType one of the above numbers and press ENTER: ");  
		scanf("%c", &choice_trim);  
		while (getchar() != '\n') {}  
		if (choice_trim >= 0x31 && choice_trim <= 0x34) { break; } // Only accept 1 through 4.  
		else { printf("\nInvalid choice!\n"); } 
	}  
	return;  
}  

void executechoice(char choice_trim) {  
	switch (choice_trim) {  
		case 0x31: trimnumbers(); // 123 etc  
			break;  

		case 0x32: trimwhitespace(); // space, tab, newline  
			break;  
		
		case 0x33: trimletters(); // ABC..., abc...  
			break;  

		case 0x34: trimspecial(); // ! ? , . etc.  
			break;  
	}  
	return;  
}  

void trimnumbers(void) {  
	int n = 0;  
	for (n = strlen(input) - 1; n >= 0; n--) {  
		if (input[n] >= 0x30 && input[n] <= 0x39) { input[n] = 0x18; }  
	}  
	return;  
}  

void trimwhitespace(void) {  
	while (1) {  
		printf("\nType S to trim SPACE, T to trim TAB, N to trim NEWLINE or A to trim all whitespace: ");  
		scanf("%c", &choice_detail);  
		while (getchar() != '\n') {}  
		if (choice_detail == 'S' || choice_detail == 'T' || choice_detail == 'A') { break; }  
		else { printf("\nInvalid input!\n"); }  
	}  
	int n = 0;  
	for (n = strlen(input) - 1; n >= 0; n--) {  
		if (choice_detail == 'S') { if (input[n] == 0x20) { input[n] = 0x18; } } // space  
		else if (choice_detail == 'T') { if (input[n] == 0x09) { input[n] = 0x18; } } // tab  
		else if (choice_detail == 'N') { if (input[n] == 0x0A) { input[n] = 0x18; } } // newline  
		else if (choice_detail == 'A') { if (input[n] == 0x20 || input[n] == 0x09 || input[n] == 0x0A) { input[n] = 0x18; } }  
	}  
	return;  
}  

void trimletters(void) {  
	while (1) {  
		printf("\nType U to trim uppercase letters, L to trim lowercase letters or A to trim all letters: ");  
		scanf("%c", &choice_detail);  
		while (getchar() != '\n') {}  
		if (choice_detail == 'U' || choice_detail == 'L' || choice_detail == 'A') { break; }  
		else { printf("\nInvalid input!\n"); }  
	}  
	int n = 0;  
	for (n = strlen(input) - 1; n >= 0; n--) {  
		if (choice_detail == 'U') { if (input[n] >= 0x41 && input[n] <= 0x5A) { input[n] = 0x18; } } // Uppercase  
		else if (choice_detail == 'L') { if (input[n] >= 0x61 && input[n] <= 0x7A ) { input[n] = 0x18; } } // Lowercase  
		else if (choice_detail == 'A') { if (input[n] >= 0x41 && input[n] <= 0x5A || input[n] >= 0x61 && input[n] <= 0x7A ) { input[n] = 0x18; } }  
	}  
	return;  
}  

void trimspecial(void) {  
	while (1) {  
		printf("\nType A to trim all special characters or S to specify which character to remove: ");  
		scanf("%c", &choice_detail);  
		while (getchar() != '\n') {}  
		if (choice_detail == 'A' || choice_detail == 'S') { break; }  
		else {  printf("\nInvalid input!\n"); }  
	}  
	int n = 0;  
	for (n = strlen(input) - 1; n >= 0; n--) {  
		if (choice_detail == 'A') { if (input[n] >= 0x21 && input[n] <= 0x2F || input[n] >= 0x3A && input[n] <= 0x40 || input[n] >= 0x5B && input[n] <= 0x60 || input[n] >= 0x7B && input[n] <= 0x7E) { input[n] = 0x18; } } // All whitespace  
	}  
	if (choice_detail == 'S') { specifyspecial(); } // Let user specify character.  
	return;  
}  

void specifyspecial(void) {  
	while (1) {  
		printf("\nEnter special character to trim and press ENTER: ");  
		scanf("%c", &choice_special);  
		while (getchar() != '\n') {}  
		if (choice_special >= 0x21 && choice_special <= 0x2F || choice_special >= 0x3A && choice_special <= 0x40 || choice_special >= 0x5B && choice_special <= 0x60 || choice_special >= 0x7B && choice_special <= 0x7E) { break; }  
		else { printf("\nNot a special character!\n"); }  
	}  
	int n = 0;  
	for (n = strlen(input) - 1; n >= 0; n--) { if (input[n] == choice_special) { input[n] = 0x18; } }  
	return;  
}  

void printresult(char input[]) {  
	printf("\nTrimmed text:\n\n%s\n", input);  
	sprintf(previous_input, "%s", input); // Save trimmed text for reuse.  
	return;  
}  

//TODO  
//Create error handling when trimming non existing characters.  
//Replace characters (uppercase/lowercase, user selected, etc).  

  • hkwln@lemmy.ml
    link
    fedilink
    English
    arrow-up
    2
    ·
    6 days ago

    I think this is more about readability and style. I have looked at your codei and changed a few things😅, maybe this helps you. This is how I would do it: (I am as well far from expert level in C)

    CODE
    #include <limits.h> //  added for INT_MIN
    #include <stdio.h>
    #include <stdlib.h> // added for exit()
    #include <string.h>
    
    // you use scanf getchar and fgets, I would  choose one
    //  Function declarations, also chooose your naming convention!
    void prompt_choice_main(char *choice);
    void prompt_choice_main_again(void);
    void prompt_input(void);
    int prompt_choice_trim(void);
    void (*execute_choice[])(void);
    void trim_numbers(void);
    void trim_whitespace(void);
    void trim_letters(void);
    void trim_special(void);
    void specify_special(void);
    void print_result(char input[]);
    
    // Global variables; I would put as much of these as parameters/structs or
    // return values because of clearer ownership and readability
    char choice_detail = 0x00;
    char choice_special = 0x00;
    char input[1000] = "";
    char previous_input[1000] = "";
    
    // Remove specific numbers, letters, punctuation or whitespace characters from
    // input.
    int main() {
      printf(
          "\nWelcome! This program trims text by removing unwanted characters.\n");
      while (1) {
        char choice_main = 0x00;
        prompt_choice_main(&choice_main);
        if (choice_main == 'T') {
          prompt_input();
          int choice_trim = prompt_choice_trim();
          execute_choice[choice_trim]();
          print_result(input);
        } else if (choice_main == 'P') {
          snprintf(input, 1000, "%s",
                   previous_input); // i would prefer snprintf instead of sprintf
                                    // because of safety
          printf("\nYou are trimming previously trimmed text: %s\n", input);
          int choice_trim = prompt_choice_trim();
          execute_choice[choice_trim]();
          print_result(input);
        } else if (choice_main == 'E') {
          printf("\nGoodbye!\n");
          exit(0);
        }
      }
      return 0;
    }
    
    // Function definitions
    void prompt_choice_main(char *choice_main) {
      while (1) {
        printf("\nPress T and ENTER to trim text");
        if (strlen(previous_input) != 0) {
          printf(", P for previously trimmed text ");
        }
        printf(" or E and ENTER to exit: ");
        *choice_main = getchar();
        while (getchar() != '\n') {
        }
        if (*choice_main == 'T' || *choice_main == 'E' || *choice_main == 'P') {
          break;
        } else {
          printf("\nInvalid input!\n");
        }
      }
    }
    
    void prompt_input(void) {
      printf("\nEnter the text that you would like to trim and press ENTER: ");
      size_t c = 0;
      do
        input[c++] = getchar();
      while (input[c] != '\n');
      input[c] = '\0';
    }
    
    int prompt_choice_trim(void) {
      while (1) {
        int choice_trim = 0;
        printf("\nWhat would you like to trim?\n1) Numbers (1, 2, 3...)\n2) "
               "Whitespace (space, tab or newline) \n3) Letters (A,B,C... "
               "a,b,c...)\n4) Special characters (!,?, . , ...)\nType one of the "
               "above numbers and press ENTER: ");
        char c;
        c = getchar();
        choice_trim = c - '0';
        while (getchar() != '\n') {
        }
        if (choice_trim < 1 || choice_trim > 4) {
          printf("\nInvalid choice!\n");
        } else {
          return choice_trim - 1;
        }
      }
      // INFO: Through the return type you can do a bit of error handling i you did
      // not already now
      return INT_MIN;
    }
    
    // Here I would use a function pointer, but your version is also perfectly fine
    void (*execute_choice[])(void) = {
        trim_numbers,    // 123 etc
        trim_whitespace, // space, tab, newline
        trim_letters,    // ABC..., abc...
        trim_special,    // ! ? , . etc.
    };
    
    // I would not replace characters with 0x18 but instead keep chars which a valid
    // and delete chars which are unvalid in a
    void trim_numbers(void) {
      size_t w = 0;
      for (size_t r = 0; input[r] != '\0'; r++) {
        if (input[r] != '0' && input[r] != '1' && input[r] != '2' &&
            input[r] != '3' && input[r] != '4' && input[r] != '5' &&
            input[r] != '6' && input[r] != '7' && input[r] != '8' &&
            input[r] != '9') {
          input[w++] = input[r];
        }
      }
      input[w] = '\0';
      return;
    }
    
    void trim_whitespace(void) {
      while (1) {
        printf("\nType S to trim SPACE, T to trim TAB, N to trim NEWLINE or A to "
               "trim all whitespace: ");
        scanf("%c", &choice_detail);
        while (getchar() != '\n') {
        }
        if (choice_detail == 'S' || choice_detail == 'T' || choice_detail == 'A') {
          break;
        } else {
          printf("\nInvalid input!\n");
        }
      }
      int n = 0;
      for (n = strlen(input) - 1; n >= 0; n--) {
        if (choice_detail == 'S') {
          if (input[n] == 0x20) {
            input[n] = 0x18;
          }
        } // space
        else if (choice_detail == 'T') {
          if (input[n] == 0x09) {
            input[n] = 0x18;
          }
        } // tab
        else if (choice_detail == 'N') {
          if (input[n] == 0x0A) {
            input[n] = 0x18;
          }
        } // newline
        else if (choice_detail == 'A') {
          if (input[n] == 0x20 || input[n] == 0x09 || input[n] == 0x0A) {
            input[n] = 0x18;
          }
        }
      }
      return;
    }
    
    void trim_letters(void) {
      while (1) {
        printf("\nType U to trim uppercase letters, L to trim lowercase letters "
               "or A to trim all letters: ");
        scanf("%c", &choice_detail);
        while (getchar() != '\n') {
        }
        if (choice_detail == 'U' || choice_detail == 'L' || choice_detail == 'A') {
          break;
        } else {
          printf("\nInvalid input!\n");
        }
      }
      int n = 0;
      for (n = strlen(input) - 1; n >= 0; n--) {
        if (choice_detail == 'U') {
          if (input[n] >= 0x41 && input[n] <= 0x5A) {
            input[n] = 0x18;
          }
        } // Uppercase
        else if (choice_detail == 'L') {
          if (input[n] >= 0x61 && input[n] <= 0x7A) {
            input[n] = 0x18;
          }
        } // Lowercase
        else if (choice_detail == 'A') {
          if (input[n] >= 0x41 && input[n] <= 0x5A ||
              input[n] >= 0x61 && input[n] <= 0x7A) {
            input[n] = 0x18;
          }
        }
      }
      return;
    }
    
    void trim_special(void) {
      while (1) {
        printf("\nType A to trim all special characters or S to specify which "
               "character to remove: ");
        scanf("%c", &choice_detail);
        while (getchar() != '\n') {
        }
        if (choice_detail == 'A' || choice_detail == 'S') {
          break;
        } else {
          printf("\nInvalid input!\n");
        }
      }
      int n = 0;
      for (n = strlen(input) - 1; n >= 0; n--) {
        if (choice_detail == 'A') {
          if (input[n] >= 0x21 && input[n] <= 0x2F ||
              input[n] >= 0x3A && input[n] <= 0x40 ||
              input[n] >= 0x5B && input[n] <= 0x60 ||
              input[n] >= 0x7B && input[n] <= 0x7E) {
            input[n] = 0x18;
          }
        } // All whitespace
      }
      if (choice_detail == 'S') {
        specify_special();
      } // Let user specify character.
      return;
    }
    
    void specify_special(void) {
      while (1) {
        printf("\nEnter special character to trim and press ENTER: ");
        scanf("%c", &choice_special);
        while (getchar() != '\n') {
        }
        if (choice_special >= 0x21 && choice_special <= 0x2F ||
            choice_special >= 0x3A && choice_special <= 0x40 ||
            choice_special >= 0x5B && choice_special <= 0x60 ||
            choice_special >= 0x7B && choice_special <= 0x7E) {
          break;
        } else {
          printf("\nNot a special character!\n");
        }
      }
      int n = 0;
      for (n = strlen(input) - 1; n >= 0; n--) {
        if (input[n] == choice_special) {
          input[n] = 0x18;
        }
      }
      return;
    }
    
    void print_result(char input[]) {
      printf("\nTrimmed text:\n\n%s\n", input);
      sprintf(previous_input, "%s", input); // Save trimmed text for reuse.
      return;
    }
    
    // TODO
    //  Create error handling when trimming non existing characters.
    //  Replace characters (uppercase/lowercase, user selected, etc).
    
    • printf("%s", name);@piefed.blahaj.zoneOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      5 days ago

      Thank you so much for this! I’ll have to digest your comments slowly, since I don’t have any knowledge of or experience with enums, structs or function pointers. YET. 😁

      Let me know if you have ko-fi or the likes and I’ll buy you a cup of coffee!

      • hkwln@lemmy.ml
        link
        fedilink
        English
        arrow-up
        2
        ·
        4 days ago

        No problem, If you have any further questions about my or your code, feel free to ask.
        That’s so kind of you😊, please don’t feel like you have to, was a pleasure to help, my ko-fi: https://ko-fi.com/hkwln

  • boob_warbler@fedinsfw.app
    link
    fedilink
    English
    arrow-up
    1
    ·
    5 days ago

    For 1, I’d like for you to think you’re telling a story, one that is really air tight and unambiguous. If you think putting all the calls in main() can help you tell that story, then so be it.

    For 2, of late industrial software development has largely moved to keeping variables as local as possible so its easier to express provenance. This has been the case for at least a good 3-4 decades now.

    At no extra cost, I’d like to give you an unsolicited advice. If you’re using modern, real C compilers like gcc or clang, I’d strongly recommend you pass -Wpedantic -pedantic-errors -Wall -Wextra on the command line.

    gcc -Wpedantic -pedantic-errors -Wall -Wextra -Werror program.c
    

    and if you’re using clang, also pass -Wmost along with the rest. Learning C is one thing. But following the standard rules right from the start, it will save you from unexpected grief later on. If you try compiling your code under these flags now, it will refuse to compile. I’d suggest you try fixing as much as you can, then go back to compiling the normal way until you get a hang of things.

    • printf("%s", name);@piefed.blahaj.zoneOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      5 days ago

      Amazing advice! Thank you so much! I have bookmarked this comment! AND I’ll create an alias for clang so it uses all those switches by default. Also, GREAT analogy with the story telling!

      • boob_warbler@fedinsfw.app
        link
        fedilink
        English
        arrow-up
        1
        ·
        5 days ago

        I’d recommend not to alias compilers like that. Rather, if you’re interested, you could just use a simple Makefile like shown below and get it over with. Save it into a file called Makefile (yes, uppercase M followed by akefile all lowercase) in the same directory as your program.c file.

        Note, I have used -std=c89 but you can delete that line or maybe even use a more modern standard such as -std=c23 if you like. If you delete, both gcc and clang will default to the latest ISO standard supported by that version of compiler.

        Also since you’re compiling only a single file, I have used program.c as input producing program executable on UNIX. To run this Makefile you need to invoke make from the same directory as Makefile on command-line as:

        make W=1
        

        to enable all the warnings and compile. If you set W=0 it will not warn or even print any diagnostic unless compiler really cannot generate the executable. You can also pass D=0 for optimised/release build, D=1 for debug build so you can backtrack in gdb. You can also pass A=1 if you want address sanitisers enabled. It will report if your program is touching or even looking at pointers/memory regions the wrong way, leaking memory or just generally doing operations that cannot guarantee correct behaviour. Passing V=1 will display the exact command executed to compile, otherwise it will silently compile.

        Here’s the full Makefile I use:

        # Control build verbosity.
        V                               ?= 0
        ifeq ($(V),1)
            Q                           :=
        else
            Q                           := @
        endif
        # Control DEBUG (1) or RELEASE (0) build.
        D                               ?= 1
        # Add some warning flags?
        W                               ?= 0
        # Add some address/undefined sanitiser flags?
        A                               ?= 1
        
        ifeq ($(shell $(CC) -v 2>&1 | grep -c "gcc version"),1)
            COMPILER                    := gnu
        else ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"),1)
            COMPILER                    := llvm
        endif
        
        # Delete environment garbage so we can generate absolutely controlled 
        LDFLAGS                         :=
        CFLAGS                          :=
        
        ifeq ($(D),1)
            CFLAGS_DEFS                 += -D_DEBUG
        else
            CFLAGS_DEFS                 += -DNDEBUG
        endif
        CFLAGS_DEFS                     += -D_XOPEN_SOURCE=600
        ifeq ($(D),0)
            CFLAGS_DEFS                 += -D_FORTIFY_SOURCE=2
        endif
        CFLAGS_DEFS                     += -D_LARGEFILE64_SOURCE=1
        CFLAGS_DEFS                     += -D_LARGEFILE_SOURCE=1
        
        ifeq ($(W),1)
            CFLAGS_STDS                 += -std=c89
            CFLAGS_STDS                 += -Wpedantic
            CFLAGS_STDS                 += -pedantic-errors
        
            CFLAGS_STDS                 += -Werror
            CFLAGS_STDS                 += -Wall
            CFLAGS_STDS                 += -Wextra
            ifeq ($(COMPILER),gnu)
                CFLAGS_STDS             += -Wbad-function-cast
                CFLAGS_STDS             += -Wcast-align
                CFLAGS_STDS             += -Wcast-qual
                CFLAGS_STDS             += -Wduplicated-branches
                CFLAGS_STDS             += -Wduplicated-cond
                CFLAGS_STDS             += -Wfloat-equal
                CFLAGS_STDS             += -Wformat-nonliteral
                CFLAGS_STDS             += -Wformat-security
                CFLAGS_STDS             += -Wformat-signedness
                CFLAGS_STDS             += -Wformat-truncation=2
                CFLAGS_STDS             += -Wformat=2
                CFLAGS_STDS             += -Winline
                CFLAGS_STDS             += -Wlogical-op
                CFLAGS_STDS             += -Wmissing-declarations
                CFLAGS_STDS             += -Wmissing-format-attribute
                CFLAGS_STDS             += -Wmissing-include-dirs
                CFLAGS_STDS             += -Wmissing-noreturn
                CFLAGS_STDS             += -Wmissing-prototypes
                CFLAGS_STDS             += -Wnested-externs
                CFLAGS_STDS             += -Wno-unused-result
                CFLAGS_STDS             += -Wnull-dereference
                CFLAGS_STDS             += -Wold-style-definition
                CFLAGS_STDS             += -Wpointer-arith
                CFLAGS_STDS             += -Wpointer-sign
                CFLAGS_STDS             += -Wredundant-decls
                CFLAGS_STDS             += -Wrestrict
                CFLAGS_STDS             += -Wreturn-type
                CFLAGS_STDS             += -Wshadow
                CFLAGS_STDS             += -Wsign-compare
                CFLAGS_STDS             += -Wsign-conversion
                CFLAGS_STDS             += -Wstrict-aliasing
                CFLAGS_STDS             += -Wstrict-prototypes
                CFLAGS_STDS             += -Wswitch-enum
                CFLAGS_STDS             += -Wtrampolines
                CFLAGS_STDS             += -Wundef
                CFLAGS_STDS             += -Wuninitialized
                CFLAGS_STDS             += -Wunreachable-code
                CFLAGS_STDS             += -Wunused
                CFLAGS_STDS             += -Wunused-but-set-parameter
                CFLAGS_STDS             += -Wunused-but-set-variable
                CFLAGS_STDS             += -Wunused-label
                CFLAGS_STDS             += -Wunused-local-typedefs
                CFLAGS_STDS             += -Wunused-parameter
                CFLAGS_STDS             += -Wunused-variable
                CFLAGS_STDS             += -Wwrite-strings
            else
                CFLAGS_STDS             += -Wmost
                CFLAGS_STDS             += -Warray-bounds-pointer-arithmetic
                CFLAGS_STDS             += -Wassign-enum
                CFLAGS_STDS             += -Wcomma
                CFLAGS_STDS             += -Wconditional-uninitialized
                CFLAGS_STDS             += -Wformat-type-confusion
                CFLAGS_STDS             += -Widiomatic-parentheses
                CFLAGS_STDS             += -Wloop-analysis
                CFLAGS_STDS             += -Wshift-sign-overflow
                CFLAGS_STDS             += -Wshorten-64-to-32
                CFLAGS_STDS             += -Wstrict-aliasing=2
                CFLAGS_STDS             += -Wstrict-overflow=5
                CFLAGS_STDS             += -Wtautological-constant-in-range-compare
                CFLAGS_STDS             += -Wthread-safety
                CFLAGS_STDS             += -Wunreachable-code-aggressive
                CFLAGS_STDS             += -Wunused
                CFLAGS_STDS             += -Wunused-argument
                CFLAGS_STDS             += -Wunused-but-set-parameter
                CFLAGS_STDS             += -Wunused-but-set-variable
                CFLAGS_STDS             += -Wunused-comparison
                CFLAGS_STDS             += -Wunused-const-variable
                CFLAGS_STDS             += -Wunused-exception-parameter
                CFLAGS_STDS             += -Wunused-function
                CFLAGS_STDS             += -Wunused-label
                CFLAGS_STDS             += -Wunused-local-typedefs
                CFLAGS_STDS             += -Wunused-macros
                CFLAGS_STDS             += -Wunused-parameter
                CFLAGS_STDS             += -Wunused-value
                CFLAGS_STDS             += -Wunused-variable
                CFLAGS_STDS             += -Wunused-volatile-lvalue
            endif
        else
        	# Disable all manners of warnings, even default ones.
        	CFLAGS_STDS                 += -w
        endif
        
        CFLAGS_OPTS                     += -fPIC
        
        # These are needed anyway.
        ifeq ($(D),1)
            CFLAGS_OPTS                 += -O0 -g3 -ggdb3
            CFLAGS_OPTS                 += -fno-omit-frame-pointer
        else
            CFLAGS_OPTS                 += -O3
            CFLAGS_OPTS                 += -ffunction-sections
            CFLAGS_OPTS                 += -fdata-sections
            CFLAGS_OPTS                 += -fmerge-all-constants
        endif
        ifeq ($(A),1)
            CFLAGS_OPTS                 += -fsanitize=address,leak,undefined
        endif
        
        # Add more include directories to your liking
        CFLAGS_INCS                     += -I.
        
        # Assemble them all into a singfle
        CFLAGS                          += $(CFLAGS_DEFS)
        CFLAGS                          += $(CFLAGS_INCS)
        CFLAGS                          += $(CFLAGS_STDS)
        CFLAGS                          += $(CFLAGS_OPTS)
        
        LDFLAGS                         += -Wl,--as-needed
        LDFLAGS                         += -Wl,--gc-sections
        LDFLAGS                         += -Wl,--no-undefined
        LDFLAGS                         += -Wl,-z,defs
        LDFLAGS                         += -Wl,-z,nocombreloc
        LDFLAGS                         += -Wl,-z,now
        LDFLAGS                         += -Wl,-z,relro
        
        
        # The $(Q)$(CC) has a real TAB before it, not space. If you copy paste from Lemmy, you might end up with spaces.
        program: program.c
        	$(Q)$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
        
        .DEFAULT_GOAL := all
        .PHONY: all
        all: program
        
        .PHONY: clean
        # The space before $(Q)$(RM) is real TAB as well.
        clean:
        	$(Q)$(RM) program