1
 
 

I have watched some developers giving advice about using C for general software development, i noticed that a not insignificant amount of them are strictly using C89, vaguely gesturing that more recent versions of C are less dependable, or more broken.

I would appreciate if anyone here can explain the specifics, as me not being a C developer (yet) and looking over the source code of some libraries which do heavily use modern C features, for example to have a defer-like macro (using attributes, or the 2 for statement trick), or generic data structures (using manual name mangling).

I understand these examples are strictly not how C is usually used, and are common in other more modern languages, which may turn some developers away from using these, my main question is "why exactly?".

I don't mind being given further reading about this, so if you have an article in mind, it too would be greatly appreciated.

note: in the title i referred to C23, but it could be anything post C89/C99 depending on the subject matter.

2
 
 

#Hello eveyone!!

D.eSystem 6.0.8 beta is the final release of D.eSystem 6, ist way more stable than the old Beta versions and it introduces a gui for the D.eSystem version app

D.eSystem 6.0.8 on github: https://github.com/D-electronics-scratch/all_D.eSystem_versions/releases

Github main page: https://github.com/D-electronics-scratch/all_D.eSystem_versions

3
submitted 3 weeks ago* (last edited 3 weeks ago) by to c/c_lang@programming.dev
 
 

D.eSystem 6.0.1 Beta This is the first beta release of D.eSystem 6. It includes several stability patches, a fully graphical Clock app, and a redesigned D.eShell interface. D.eSystem 6 page: https://github.com/D-electronics-scratch/D.eSystem

4
 
 

Hello everyone!!

D.eSystem 6.0.6 alpha introduces the first GUI for my operating system D.eSystem 6.

The system is currently keyboard‑only, but mouse support is planned for future versions.

The usage is similar to D.eSystem 6.0.5, but now with a graphical interface, and the calculator also received a GUI version.

Requirements:

64‑bit CPU

UEFI firmware (Legacy BIOS is not supported)

D.eSystem 6.0.6 alpha runs on any VM (QEMU, VirtualBox, VMware) and on real hardware.

Download D.eSystem 6.0.6 alpha here: https://github.com/D-electronics-scratch/D.eSystem-6.0.6-alpha-iso-download

5
 
 

D.eSystem 6.0.5 alpha is a custom OS that runs on real hardware and in QEMU, VirtualBox, and VMware.

This version includes the new D.eShell and three programs.

The OS is text‑based for now, but 6.0.6 alpha will introduce a GUI. A big roadmap is already planned.

ISO download: https://github.com/D-electronics-scratch/D.eSystem-6.0.5-alpha-iso-download/blob/main/template.iso

6
 
 

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

7
submitted 1 month ago* (last edited 1 month ago) by to c/c_lang@programming.dev
 
 

Environment\
Compiler Clang on Termux on Samsung's One UI 7 on a Samsung Galaxy Tab A9+

The title is an assumption on it's own, so feel free to correct it/me!

I was experimenting with sanitizing user input, read to a character array with fgets. Specifically, I was trying to have a for loop remove (skip) certain input. Here is the code:

for (n = strlen(input) - 1; n >= 0; n--) { if (input[n] >= 0x30 && input[n] <= 0x39 || input[n] == ' ' || input[n] == '\t') { input[n] = 0x18; } }  

While the program does behave as I want it to, I don't understand why it seemlingy by default understands that the various hex codes refer to the character encoding as per the ASCII table. I cated my tablet's filesystem encoding at /sys/fs/f2fs/dm-44/encoding, which yielded UTF-8. If I understand it correctly, the first 128 code points of Unicode are the same as ASCII's. But according to this article on Wikipedia, there are no hexadecimal references in Unicode, only octal and decimal.

If the underlying filesystem uses UTF-8, and Unicode code points are not referred to by hex, how then does my compiler (Clang) understand what ASCII code points I'm referring to?

Is there some conversion going on under the hood that I am not aware of? I did find a libxml2/libxml/encoding.h, which contains comments about some conversion to and from UTF-8. Is this it? I can't make head or tails of it because of my limited C knowledge...

8
 
 

For instance, I wanted to see how printf is written. I looked into the stdio.h file, but there, I could only find the function declaration, no definition.

9
 
 

cross-posted from: https://infosec.pub/post/47574072

Hello lemmings, I made a program to ping every IPv4 address and collect data on respondents. I am almost done, but I want feedback on things I should change or how I can improve my current record of 5,000 pings / second.

I am currently aware that I need to properly parse the data I receive on the receive socket, since it's possible the TTL router messages might be confused as replies. ICMP is used on networks to inform other machines of network problems.

One issue I'm aware of is the tuning that has to go into maximizing throughput while also avoiding a total system freeze. My code seems to spend too much time opening sockets that it leaves no room for the actual OS. My only fix currently is limiting the CPU time to the ping timeout I used.

The overall program works like this: It keeps a linked list / pool of task objects. All objects are initially in the "free list" and then when they become associated with a socket, they move to the "active list". The program first checks for updated sockets with epoll which results in like 5% of sockets giving a response. It then closes any tasks that have timed out via linked list in O(1) each. The slow part is when it creates new sockets, since it doesn't really know when to stop, besides when the non-blocking socket informs it that it would block. I implemented a time limit on sending that is currently the maximum of the ping timeout. To increase throughput it seems like I need to streamline how I send ICMP packets.

https://github.com/bneils/PingStorm

10
 
 

Good afternoon! How are you all holding up today? I "accidentally" ate piece of cake at the cafe I'm currectly sitting in, even though I had promised myself not to eat sugar until next week. Fail. 😅

Don't mind the English language, since this is an excerpt from a larger piece of code.

If I enter anything other than 'Y' and 'N' using a single character, the code works as I want it to, but, naturally, if I enter anything other than 'Y' and 'N' multiple times, the if is executed the same amount of times as characters entered, which is ugly. Trying to limit this with %1c also doesn't work, since I suppose that only works with strings? Is this a limitation of scanf or rather how the logic is implemented?

Feel free to NOT provide the correct answer right away, but instead, give me the topic or the function to read up on. 😊

	char letter = '\0';  
	while(1) {  
		printf("nter the letter 'Y' or 'N': ");  
		scanf(" %c", &letter);  
		if (letter != 'Y' && letter != 'N') { //"broken" because multicharacter input executes this condition that many times.  
			printf("You have to enter 'Y' or 'N'! You have entered %c!\nE", letter);  
		}  
		else { break; }  
	}  
	printf("Good job! You have entered: %c.\n", letter);  

11
 
 

Up until recently, have been trying to validate user input by writing lengthy if-statetments nested in while-loops. I usually have the while-loop check that the function that takes input - for instance getchar() - is not EOF and the if-statement checking whether input is of the desired data type and/or size. But then I noticed people doing something similar with infinite loops while(1) and for(;;).

While I understand that these loops are infinite because there is no condition to check against in for(;;) and because the condition is always true in while(1), I wonder if there is a more pedagogical (?) way of expressing the same thing. Like a proof of concept, or like what's going on at the electronic/logic level, if one were to draw this on a schematic with logic gates.

Or am I perhaps overthinking it and there is "simply" a signal/transistor somewhere that is always on/1/true/has the approproate votlage? Feels like "fooling" the machine by writing while(1) or for (;;) ....

12
 
 

Is there perhaps some other, better way to do it? Perhaps one with which clang doesn't give me "unused result" warnings?

MODS: If you deem it inappropriate for me to continuously ask for guidance here, please let me know. 😊

#include <stdio.h>  

void executechoice(int choice);		
void printsavedpins(int pin_storage[]);  
void promptnewpin(void);  
void checkpinlength(int pin);  
void checkpinmatch(int pin);  
void updatepinstorage(int pin);  

int pin = 0;  
int pin_storage[10] = {0};  
int storage_index = 0;  
const int storage_limit = 10;  

//Prompt user for action.  
int main() {  

	int choice = 0;  
	printf("What would you like to do? (V)iew your saved pins, (S)ave a new pin or (E)xit? "); 
	while ((choice = getchar()) != EOF) {  
		getchar(); //clang gives 'unused result' warning but '\n' needs to be removed.  
		if (choice == 'E' || choice == 'e') { break; }  
		else {  
			executechoice(choice);  
			getchar(); //clang gives 'unused result' warning but '\n' needs to be removed.  
			printf("What would you like to do next? (V)iew your saved pins, (S)ave a new pin or (E)xit? ");  
		}  
	}  
	printf("Goodbye!\n");  
	return 0;  
}  

//Function definitions  
void executechoice(int choice) {		
	if (choice == 'V' || choice == 'v') { printsavedpins(pin_storage); }  
	else if (choice == 'S' || choice == 's') { promptnewpin(); }  
	else { printf("Invalid choice! What would you like to do? (V)iew your saved pins, (S)ave a new pin or (E)xit? "); }  
}  

void printsavedpins(int pin_storage[]) {  
	for (int i = 0; i < storage_limit; i++) printf("Pin %d: %d\n", i + 1, pin_storage[i]);  
}  

void promptnewpin(void) {  
	
	printf("Enter new pin: ");  
	scanf("%d", &pin);  
	checkpinlength(pin);  
}  

void checkpinlength(int pin) {  
	
	if (pin < 1000*100) {  
		printf("Pin has to be at least six digits!\n");  
		promptnewpin();  
	}  
	else checkpinmatch(pin);  
}  

void checkpinmatch(int pin) {  

	int check = 0;  
	printf("Verify your new pin: ");  
	scanf("%d", &check);  
	if (check != pin) {  
		printf("Mismatch! ");  
		promptnewpin();  
	}  
	else updatepinstorage(pin);  
}  

void updatepinstorage(int pin) {  

	pin_storage[storage_index] = pin;  
	storage_index++;  
	if (storage_index >= storage_limit) { storage_index = 0; }  
	printf("New pin saved successfully!\n");  
}  
13
Aesthetics: goto or not (piefed.blahaj.zone)
submitted 2 months ago* (last edited 2 months ago) by to c/c_lang@programming.dev
 
 

Good day! How are you this gloomy, rainy afternoon?

I just realized - through experimentation, naturally 😂 - that I can return whole printf()s into main. Mind blowing. Anyway, I would much appreciate any input on how to write my leapYear function more aesthetically pleasing. I tried slapping the printf statements at the end of leapYear or at the end of each if statement. Still feels repetitive...

Also, as it stands, I'm having leapYear return int as per the declaration and definition. But I am returning printf() statements. Why does this work? I know that, for instance, char is int under the hood, using the machine's underlying character table, for instance ASCII. Is the explanaition something similar to this?

Thank you in advance! 😊

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

int leapYear(int year);  

int main() {  

	int year = 0;  

	printf("Enter the year that you would like to check and press ENTER: ");  
	
	scanf("%d", &year);  
	leapYear(year);  
	
	return 0;  
}  

int leapYear(int year) {  

	char wasiswill[12] = "";  

    	if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {  
	    	if (year < 2026) strcpy(wasiswill,"was");  
	    	if (year == 2026) strcpy(wasiswill, "is");  
        	if (year > 2026) strcpy(wasiswill, "will be");  
  	        goto EXIT_LEAP;  
	}  
	else {  
		if (year < 2026) {  
			strcpy(wasiswill,"was");  
			goto EXIT_NLEAP1;  
		}  
		else if (year == 2026) {  
			strcpy(wasiswill, "is");  
			goto EXIT_NLEAP2;  
		}  
		else if (year > 2026) {  
			strcpy(wasiswill, "will not be");  
			goto EXIT_NLEAP3;  
		}  
	}  
EXIT_LEAP: return printf("%d %s a leap year.\n", year, wasiswill);  
EXIT_NLEAP1: return printf("%d %s not a leap year.\n", year, wasiswill);  
EXIT_NLEAP2: return printf("%d %s not a leap year.\n", year, wasiswill);  
EXIT_NLEAP3: return printf("%d %s a leap year.\n", year, wasiswill);  
}  
14
submitted 2 months ago* (last edited 2 months ago) by to c/c_lang@programming.dev
 
 

Thank you all for your kind, patient and educative responses when I obnoxiously post amateur questions! 💙 While I cannot make any promises because of how my brain works, I am almost ready to continue reading The C Programming Language, 2nd Edition. I just want to experiment a little bit with error handling, specifically how to handle wrong input (char VS. int, etc.) and also to learn to indentify code that runs the risk of overflow/underflow.

Question: what errors do you recommend checking for and handling?

Meanwhile, thank you all! 🥰

#include <stdio.h>  

//Function declarations  
int newPin();  
int checkPin(int i);  

//Program that prompts for, verifies and saves pins temporarily into an array  
int main() {  

	//New pin  
	int pin = 0;  

	//History  
	int history[10] = {0,0,0,0,0,0,0,0,0,0};  
	int history_limit = 10;  
	int history_index = 0;  

	printf("Hello there! What would you like to do? (V)iew your saved pins, (S)ave a new pin or (E)xit: ");  
	int choice = 0;  
	while ((choice = getchar()) != EOF) {  
		switch (choice) {  
			case ('V'): { //Display saved pins  
				printf("\nYour saved pins are:\n\n");  
				for (int i = 0; i < history_limit; i++) printf("%d\n", history[i]);  
				printf("\nWhat would you like to do next? (V)iew your saved pins, (S)ave a new pin or (E)xit: ");  
				break;  
			}  
			case('S'): { //Prompt for and verify newly entered pin  
				pin = newPin();  
				if (checkPin(pin) == pin) {  
					history[history_index] = pin;  
					history_index++;  
					if (history_index >= history_limit) history_index = 0;  
				}  
				break;  
			}  
			case ('E'): goto EXIT; //Terminate program  
		}  
	}  
EXIT:	printf("\nGoodbye!\n");  
	return 0;  
}  

//Function definitions  
//Prompt user to enter a new pin  
int newPin() {  
	
	int pin = 0;  
	
	printf("This enter your pin: ");  
	scanf("%d", &pin);  
	getchar();  

	return pin;  
}  

//Verify newly entered pin  
int checkPin (int i) {  

	int check = 0;  
	
	printf("Confirm your new pin: ");  
	while((scanf("%d", &check)) != EOF) {  
		if (check != i) printf("Mismatch! Confirm your new pin: ");  
		else if (check == i) { 
			printf("Success! Your new pin is %d. What would you like to do next? (V)iew your saved pins, (S)ave a new pin or (E)xit: ", i);  
			goto EXIT;  
		}  
	}  
EXIT:	return i;  
}  

//TODO  
//Error handling (overflow, input data type, other?)  
15
 
 

Hello there! I am playing around at random for now before continuing reading the litterature that I am using to learn C.

What is a less "ugly" way to break out the while loop at the last if-else statement than leaving else empty? I guess I could have avoided this if I knew how to terminate the program at the switch - case (E) other that break -ing out of it as I am now, in other words, not having to "climb" out of switch , then while and then reaching "Goodbye!".

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

//Save "pins" in an array with an upper limit of ten pins. "Saved pins" resets if the upper limit is reached.  
int main(void) {  

	int pin = 0;  
	int check = 0;  

	//Saved pins  
	int pin_history[10]={0,0,0,0,0,0,0,0,0,0};  
	int pin_history_index = 0;  
	int pin_history_limit = 10;  

	int choice = 0;  

	printf("Enter your new pin: ");  
	scanf("%d", &pin);  
	getchar();  
	printf("Confirm your new pin: ");  
	while ((scanf("%d", &check))) {  
		if (check != pin) {  
			getchar();  
			printf("\nMismatch! Confirm your new pin: ");  
		}  
		else if (check == pin) {  
			pin_history[pin_history_index] = pin;  
			pin_history_index = pin_history_index + 1;  
			if (pin_history_index >= pin_history_limit) pin_history_index = 0;  
			printf("\nYour new pin has been saved successfully!\n");  
			break;  
		}  
	}  

	printf("What would you like to do next?\n\n(V)iew your saved pins\n(S)ave another pin\n(E)xit\n");  
	while ((choice = getchar()) != EOF) {  
		switch (choice) {  
			case ('V'):  
				printf("\nYour saved pins are:\n");  
				for (int i = 0; i < pin_history_limit; ++i) {  
				printf("%d\n", pin_history[i]);  
				}  
				printf("\nWhat would you like to do next?\n(V)iew your saved pins\n(S)ave another pin\n(E)xit\n");  
				break;  
			case ('S'): {  
				printf("\nEnter your new pin: ");  
				scanf("%d", &pin);  
				getchar();  
				printf("Confirm your new pin: ");  
				while ((scanf("%d", &check))) {  
					if (check != pin) {  
						getchar();  
						printf("\nMismatch! Confirm your new pin: ");  
					}  
					else if (check == pin) {  
						getchar();  
						pin_history[pin_history_index] = pin;  
						pin_history_index = pin_history_index + 1;  
						if (pin_history_index >= pin_history_limit) pin_history_index = 0;  
						printf("\nYour new pin has been saved successfully!\n");  
						printf("What would you like to do next?\n\n(V)iew your saved pins\n(S)ave another pin\n(E)xit\n");  
						break;  
					}  
				}  
				break;  
			}  
			case ('E'): break;  
		}  
		if (choice == 'E') break;  
		else;  
	}  
	printf("\nGoodbye!\n");  
	return 0;  
}  
16
 
 

I was experimenting with while loops, testing what happens if I condition the loop with == 0/1/EOF versus != 0/1/EOF. Obviously, this shows, more than anything else, my lack of understanding of the logic behind these operations, but it also taught me that getchar() will return the ASCII value of chars and ints if I use the format specifier %d. Also, that scanf() isn't as "forgiving", causing infinite loops, among other things, if I under certain conditions enter a char.

Is there anything else that I could learn/take away here, or was this a waste of time? 😅

The various results are commented next to the respective loops.

#include <stdio.h>  

int main() {  

	int number = 0;  

	printf("Enter a number: ");  

/*  
	while((scanf("%d", &number)) != 1) { //Success with "== 1" or "!= 0/EOF", terminates after int input with "== 0/EOF" or "!= 1", terminates after char input with "== 1" or"!= 0", infinite loop after char input with "== 0" or "!= 1/EOF".  
		printf("You have entered number %d\n", number);  
		printf("Enter a new number: ");  
	}  
*/  

/*  
	while ((number = getchar()) == EOF) { //Success with "!= 0/1/EOF", terminates after input with "== 0/1/EOF".  
		getchar();  
		printf("You have entered number %d\n", number);  
		printf("Enter a new number: ");  
	}  
*/  

	return 0;  
}  

17
 
 

Good day! (Yes to all interpretations thereof.)

I am a beginner at C, studying on my own because it's fun and my goal is to "simply" gain a better understanding of how machines work under the hood. I just successfully wrote a bidirectional Celcius/Fahrenheit converter that also takes some user input. As a next step, I would like to save conversion history. Do I have to save to a file outside the program or can I temporarily save history in a variable or an array and give the user the choice to check history by displaying the contents of that variable/array? If the answer is saving to an outside file, then I digress, as this is next on my "curriculum" (still self studies). If the answer is that I can save previous input into variables or an array, how do I make a - for instance - for loop go through the elements of that array, assigning one user input (temperature conversion) in one element at a time?

Also, if this is more advanced than what I am make it sound like, please let me know, and I'll let it be for the time being.

#include <stdio.h>  

//Function declarations  
float toCelcius(float fahrenheit);  
float toFahrenheit(float celcius);  

//Bidirectional temperature converter  

int main() {  

	int f_value;  
	int c_value;  
	int choice;  

	printf("\nWelcome to this Fantasic Bidirectional Temperature Converter!\n");  
	printf("\nWhat would you like to do? Press f + enter to convert Fahrenheit to Celcius, c + enter to convert Celcius to Fahrenheit or ctrl + c to exit: ");  
			
	while ((choice = getchar()) != EOF) {  
		if (choice != 'f' && choice != 'c') {  
			printf("Goodbye!\n"); //ctrl + c does not allow for this to be displayed.  
		}	
		if (choice == 'f') {  
			printf("\nEnter the temperature in Fahrenheit: ");  
			scanf("%d", &f_value);  
			getchar();  
			printf("\n%d degrees Fahrenheit is %.1f degrees Celcius.\n", f_value, toCelcius(f_value));  
		}  
		if (choice == 'c') {  
			printf("\nEnter the temperature in Celcius: ");  
			scanf("%d", &c_value);  
			getchar();  
			printf("\n%d degrees Celcius is %.1f degrees Fahrenheit.\n", c_value, toFahrenheit(c_value));  
		}  
		printf("\nWhat would you like to do next? Press f + enter to convert Fahrenheit to Celcius, c + enter to convert Celcius to Fahrenheit or ctrl + c to exit: ");  
	}  
	return 0;  
}  

//Function definitions  
float toCelcius(float fahrenheit) {  
	return (5.0 / 9.0) * (fahrenheit - 32.0);  
}  

float toFahrenheit(float celcius) {  
	return (celcius * 1.8) + 32;  
}  
18
 
 

hello, i am a student coder and i am spending more time trying to handle the f...ing input than i spend on algorithmization of the problem. could someone recommend some good study source, please?

i would like both the explanatory part, as well as some set of practice exercises that would really cover all possible variations.

thank you.

19
20
21
 
 

Major new features:

  • The ISO C23 free_sized, free_aligned_sized, memset_explicit, and memalignment functions have been added.

  • As specified in ISO C23, the assert macro is defined to take variable arguments to support expressions with a comma inside a compound literal initializer not surrounded by parentheses.

  • For ISO C23, the functions bsearch, memchr, strchr, strpbrk, strrchr, strstr, wcschr, wcspbrk, wcsrchr, wcsstr and wmemchr that return pointers into their input arrays now have definitions as macros that return a pointer to a const-qualified type when the input argument is a pointer to a const-qualified type.

  • The ISO C23 typedef names long_double_t, _Float32_t, _Float64_t, and (on platforms supporting _Float128) _Float128_t, introduced in TS 18661-3:2015, have been added to <math.h>.

  • The ISO C23 optional time bases TIME_MONOTONIC, TIME_ACTIVE, and TIME_THREAD_ACTIVE have been added.

  • On Linux, the mseal function has been added. It allows for sealing memory mappings to prevent further changes during process execution, such as changes to protection permissions, unmapping, relocation to another location, or shrinking the size.

  • Additional optimized and correctly rounded mathematical functions have been imported from the CORE-MATH project, in particular acosh, asinh, atanh, erf, erfc, lgamma, and tgamma.

  • Optimized implementations for fma, fmaf, remainder, remaindef, frexpf, frexp, frexpl (binary128), and frexpl (intel96) have been added.

  • The SVID handling for acosf, acoshf, asinhf, atan2f, atanhf, coshf, fmodf, lgammaf/lgammaf_r, log10f, remainderf, sinhf, sqrtf, tgammaf, y0/j0, y1/j1, and yn/jn was moved to compat symbols, allowing improvements in performance.

  • Experimental support for building with clang has been added. It requires at least clang version 18, aarch64-linux-gnu or x86_64-linux-gnu targets, and a libgcc compatible runtime (including libgcc_s.so for pthread cancellation and backtrace runtime support).

  • On Linux, the openat2 function has been added. It is an extension of openat and provides a superset of its functionality. It is supported only in LFS mode and is a cancellable entrypoint.

  • On AArch64, support for 2MB transparent huge pages has been enabled by default in malloc (similar to setting glibc.malloc.hugetlb=1 tunable).

  • On AArch64 Linux targets supporting the Scalable Matrix Extension (SME), the clone() system call wrapper will disable the ZA state of the SME.

  • On AArch64 targets supporting the Branch Target Identification (BTI) extension, it is possible to enforce that all binaries in the process support BTI using the glibc.cpu.aarch64_bti tunable.

  • On AArch64 Linux targets supporting at least one of the branch protection extensions (e.g. Branch Target Identification or Guarded Control Stack), it is possible to use LD_DEBUG=security to make the dynamic linker show warning messages about loaded binaries that do not support the corresponding security feature.

  • On AArch64, vector variants of the new C23 exp2m1, exp10m1, log10p1, log2p1, and rsqrt routines have been added.

  • On RISC-V, an RVV-optimized implementation of memset has been added.

  • On x86, support for the Intel Nova Lake and Wildcat Lake processors has been added.

  • The test suite has seen significant improvements in particular around the scanf, strerror, strsignal functions and multithreaded testing.

  • Unicode support has been updated to Unicode 17.0.0.

  • The manual has been updated and modernized, in particular also regarding many of its code examples.

22
submitted 6 months ago by to c/c_lang@programming.dev
 
 

For all the rightful criticisms that C gets, GLib does manage to alleviate at least some of it. If we can’t use a better language, we should at least make use of all the tools we have in C with GLib.

This post looks at the topic of ownership, and also how it applies to libdex fibers.

23
 
 

I thought the book I'm reading had typos when I read code that uses this:

uint32_t src = 0xf0;
uint32_t dest = 0x400;

int main() {
    *&dest = *&src;
}

However if you take a look at the decompiled version on godbolt: link this correctly takes the value at the address stored in src, and copies it to the address in dest.

I'd love some help understanding what going on. The code looks like nonsense to me, "*&" should "cancel out" IMO.

========

Meanwhile here's what I thought the correct code would be:

uint32_t src = 0xf0;
uint32_t dest = 0x400;

int main() {
    *(uint32_t*) dest = *(uint32_t*) src;
}

Doesn't do what's expected, see decompiled: link. What's wrong with this?

When the RHS is a constant it works fine, and seems to be a common pattern people use.

24
submitted 6 months ago* (last edited 6 months ago) by to c/c_lang@programming.dev
 
 

I'm trying to write a linker file to get C code running on a risc-v MCU (using riscv64-unknown-elf toolchain). My linker script looks like this, simplified:

MEMORY {
        IRAM (rx) : ORIGIN = 0x00000000, LENGTH = 1024
}

ENTRY(_start)

SECTIONS {
    .text : ALIGN(4) {
        *(.text)
    } >IRAM

...

readelf -h correctly shows the entry point's address to be the same as where _start is in the output executable. But I want _start to be at 0x0, not somewhere else, so that when I objcopy it to a flat binary, the start code will be at the beginning. How can I do this?

Right now I'm having the _start function go in a new section called ".boot" I've defined in the C file using __attribute__((section(".boot"))), then, placing this at the start of .text in the linker script like so

...
    .text : ALIGN(4) {
        *(.boot)
        *(.text)
...

But IDK if this how it should be done.

Thanks in advance :)

25
view more: next ›