Skip to content

Commit 396a2cd

Browse files
committed
Update bit manipulation functions to use unsigned types for safety
- Modified setbits.c and invert.c to use ~0U instead of ~0 to prevent undefined behavior when left-shifting signed values. - Updated comments to clarify the importance of using unsigned types for bit manipulation. - Adjusted minscanf.c to use unsigned int for octal and hexadecimal inputs to match format specifier requirements, ensuring correct data handling across platforms.
1 parent 3bf582c commit 396a2cd

File tree

4 files changed

+20
-11
lines changed

4 files changed

+20
-11
lines changed

chapter_2/exercise_2_06/setbits.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ int main(void) {
2424
unsigned int setbits(int x, int p, int n, int y) {
2525
++p; // First position is 0
2626

27-
unsigned int mask1 = (~(~(~0 << n) << p) & x);
28-
unsigned int mask2 = (~(~0 << n) & y) << p;
27+
// Use ~0U (unsigned) instead of ~0 (signed) to avoid undefined behavior
28+
// when left-shifting. Left-shifting a negative signed value is undefined.
29+
unsigned int mask1 = (~(~(~0U << n) << p) & x);
30+
unsigned int mask2 = (~(~0U << n) & y) << p;
2931

3032
return mask1 | mask2;
3133
}

chapter_2/exercise_2_07/invert.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ int main(void) {
2323
unsigned int invert(int x, int p, int n) {
2424
++p; // First position is 0
2525

26-
unsigned int mask1 = ~(~0 << n) << p;
26+
// Use ~0U (unsigned) instead of ~0 (signed) to avoid undefined behavior
27+
// when left-shifting. Left-shifting a negative signed value is undefined.
28+
unsigned int mask1 = ~(~0U << n) << p;
2729
unsigned int mask2 = ~mask1 & x;
2830

2931
return mask2 | ~x;

chapter_7/exercise_7_04/minscanf.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ void minscanf(const char *format, ...);
77
int main(void) {
88
int decimal;
99
int integer;
10-
int octal;
11-
int unsigned_decimal;
12-
int hexadecimal_integer;
10+
// Use unsigned int for %o and %x to match the format specifier requirements
11+
unsigned int octal;
12+
unsigned int unsigned_decimal;
13+
unsigned int hexadecimal_integer;
1314
char character;
1415
char str[100];
1516
float float_point_number;
@@ -54,15 +55,18 @@ void minscanf(const char *format, ...) {
5455
break;
5556

5657
case 'o':
57-
scanf("%o", va_arg(arg_p, int *));
58+
// %o expects unsigned int *, not int * (octal values are unsigned)
59+
scanf("%o", va_arg(arg_p, unsigned int *));
5860
break;
5961

6062
case 'u':
6163
scanf("%u", va_arg(arg_p, unsigned int *));
6264
break;
6365

6466
case 'x':
65-
scanf("%x", va_arg(arg_p, int *));
67+
// %x expects unsigned int *, not int * (hexadecimal values are
68+
// unsigned)
69+
scanf("%x", va_arg(arg_p, unsigned int *));
6670
break;
6771

6872
case 'c':

chapter_8/exercise_8_05/fsize.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ void fsize(char *name) {
6161

6262
// Printed in a similary fashion to ls -l
6363
print_file_flags(buffer.st_mode);
64-
// Using %hu (unsigned short) instead of %lu because st_nlink is nlink_t
65-
// which is typically unsigned short, not unsigned long
66-
printf("%hu ", buffer.st_nlink);
64+
// Cast to unsigned long and use %lu for portability: nlink_t varies by
65+
// platform (unsigned short on macOS, unsigned long on Linux). The cast
66+
// ensures consistent formatting across platforms.
67+
printf("%lu ", (unsigned long)buffer.st_nlink);
6768
print_file_user(buffer.st_uid);
6869
print_file_group(buffer.st_gid);
6970
print_file_size(buffer.st_size);

0 commit comments

Comments
 (0)