Branch data Line data Source code
1 : : #include "rational.h"
2 : : #include <errno.h>
3 : :
4 : : // A utility function to reverse a string
5 : 21 : static void reverse(
6 : : char str[],
7 : : size_t length)
8 : : {
9 : 21 : size_t start = 0;
10 [ + - ]: 21 : size_t end = length > 0 ? length - 1 : 0; // Guard against empty strings
11 : :
12 [ + + ]: 87 : while(start < end)
13 : : {
14 : 66 : char temp = str[start];
15 : 66 : str[start] = str[end];
16 : 66 : str[end] = temp;
17 : 66 : end--;
18 : 66 : start++;
19 : : }
20 : 21 : }
21 : :
22 : : /**
23 : : * @brief Converts an integer to a string representation
24 : : *
25 : : * @param value The integer value to convert
26 : : * @param str The destination string buffer
27 : : * @param base The base for conversion (2-36)
28 : : * @return char* Pointer to the resulting string
29 : : *
30 : : * @note The buffer should be large enough to hold the result
31 : : * @note Supports negative numbers only in base 10
32 : : * @note For invalid base (not in 2-36), sets errno = EINVAL,
33 : : * writes an empty string, and returns str
34 : : * @note If str is NULL, sets errno = EINVAL and returns NULL
35 : : */
36 : 33 : char *itoa(
37 : : int num,
38 : : char *str,
39 : : unsigned int base)
40 : : {
41 : 33 : size_t i = 0;
42 : 33 : bool isNegative = false;
43 : : unsigned int unum; // Use unsigned int for calculations
44 : :
45 [ + + ]: 33 : if(str == NULL)
46 : : {
47 : 2 : errno = EINVAL;
48 : 2 : return NULL;
49 : : }
50 : :
51 [ + + + + ]: 31 : if(base < 2 || base > 36)
52 : : {
53 : 6 : errno = EINVAL;
54 : 6 : str[0] = '\0';
55 : 6 : return str;
56 : : }
57 : :
58 : : /* Handle 0 explicitly, otherwise empty string is
59 : : * printed for 0 */
60 [ + + ]: 25 : if(num == 0)
61 : : {
62 : 4 : str[i++] = '0';
63 : 4 : str[i] = '\0';
64 : 4 : return str;
65 : : }
66 : :
67 : : /* Handle negative numbers */
68 [ + + + + ]: 21 : if(num < 0 && base == 10)
69 : : {
70 : : /* The number is negative and we are converting to base 10.
71 : : * In this case we want to print a leading '-' sign and work
72 : : * with the absolute value of the number. For other bases we
73 : : * will treat the value as unsigned and show its bit pattern.
74 : : */
75 : 4 : isNegative = true;
76 : :
77 : : /* IMPORTANT:
78 : : * We must NOT write: (unsigned int)(-num)
79 : : * because the expression (-num) is evaluated in signed int,
80 : : * which is undefined behavior when num == INT_MIN
81 : : * (e.g. -2147483648 on a 32-bit system), since +2147483648
82 : : * cannot be represented in a signed int.
83 : : *
84 : : * To avoid this, we first cast num to unsigned int, and only
85 : : * then apply the unary minus. The unary minus on an unsigned
86 : : * type is well-defined: it performs modular arithmetic
87 : : * (2^N - value), so it never overflows.
88 : : *
89 : : * Example for a 32-bit int:
90 : : * num = INT_MIN = -2147483648
91 : : * (unsigned)num = 0x80000000 (2147483648u)
92 : : * -(unsigned)num = 0x80000000 (still 2147483648u)
93 : : * This is exactly the magnitude we need for INT_MIN.
94 : : */
95 : 4 : unum = (unsigned int)(-(unsigned int)num);
96 : : } else {
97 : : /* For non-negative numbers, or for any base other than 10,
98 : : * we simply convert the value to unsigned.
99 : : *
100 : : * - If num >= 0, this just gives the same numeric value.
101 : : * - If num < 0 and base != 10, the result is the unsigned
102 : : * value modulo 2^N, which is useful for hexadecimal or
103 : : * binary dumps of the underlying representation.
104 : : */
105 : 17 : unum = (unsigned int)num;
106 : : }
107 : :
108 : : /* Process individual digits */
109 [ + + ]: 156 : while(unum != 0)
110 : : {
111 : 135 : int rem = (int)(unum % base);
112 [ + + ]: 135 : str[i++] = (rem > 9) ? (char)(rem - 10 + 'A') : (char)(rem + '0');
113 : 135 : unum = unum / base;
114 : : }
115 : :
116 : : /* If number is negative, append '-' */
117 [ + + ]: 21 : if(isNegative)
118 : : {
119 : 4 : str[i++] = '-';
120 : : }
121 : :
122 : 21 : str[i] = '\0'; // Append string terminator
123 : :
124 : : // Reverse the string
125 : 21 : reverse(str,i);
126 : :
127 : 21 : return str;
128 : : }
129 : :
130 : : #if 0
131 : : #include <limits.h>
132 : : #include <errno.h>
133 : : /// Test
134 : :
135 : : static void test_conversion(
136 : : int value,
137 : : unsigned int base,
138 : : const char *string)
139 : : {
140 : : char buffer[66]; /* 64 bits + sign + null terminator */
141 : : itoa(value,buffer,base);
142 : :
143 : : /* Print original value in decimal and result in specified base */
144 : : printf("Value: %d (decimal)\n",value);
145 : : printf("Base %2d result: %s, %s\n",base,buffer,string);
146 : : printf("-------------------\n");
147 : : }
148 : :
149 : : /**
150 : : * @brief Test program for itoa function
151 : : *
152 : : * @note Tests edge cases and different bases with special focus on
153 : : * negative numbers and MIN/MAX integer values
154 : : */
155 : : static void test_itoa(void)
156 : : {
157 : : /* Test extreme values */
158 : : printf("=== Testing extreme values ===\n");
159 : : test_conversion(INT_MAX,10,"2147483647");
160 : : test_conversion(INT_MIN,10,"-2147483648");
161 : : test_conversion(INT_MIN,16,"Should show in hex");
162 : :
163 : : /* Test regular cases */
164 : : printf("\n=== Testing regular values ===\n");
165 : : test_conversion(255,16,"FF");
166 : : test_conversion(255,2,"11111111");
167 : : test_conversion(-255,10,"-255");
168 : :
169 : : /* Test zero handling */
170 : : printf("\n=== Testing zero ===\n");
171 : : test_conversion(0,10,"0");
172 : : test_conversion(0,16,"0");
173 : : test_conversion(0,2,"0");
174 : :
175 : : /* Test larger bases */
176 : : printf("\n=== Testing different bases ===\n");
177 : : test_conversion(12345,36,"Maximum supported base");
178 : : test_conversion(12345,16,"Common hex value");
179 : : test_conversion(12345,8,"Octal");
180 : :
181 : : /* Test negative values in different bases */
182 : : printf("\n=== Testing negative values ===\n");
183 : : test_conversion(-12345,10,"Only base 10 shows negative sign");
184 : : test_conversion(-12345,16,"Should show unsigned hex");
185 : : test_conversion(-1,2,"All bits set");
186 : :
187 : : printf("\n=== Few more examples ===\n");
188 : : char buffer[33]; /* Buffer for 32-bit integer */
189 : :
190 : : /* Decimal conversion */
191 : : itoa(12345,buffer,10);
192 : : puts(buffer);
193 : :
194 : : /* Hexadecimal conversion */
195 : : itoa(255,buffer,16);
196 : : puts(buffer);
197 : :
198 : : /* Binary conversion */
199 : : itoa(15,buffer,2);
200 : : puts(buffer);
201 : :
202 : : /* Negative number */
203 : : itoa(-789,buffer,10);
204 : : puts(buffer);
205 : :
206 : : /* Zero case */
207 : : itoa(0,buffer,10);
208 : : puts(buffer);
209 : :
210 : : char str[100];
211 : : printf("Number: %d\nBase: %d\tConverted String: %s\n",1567,10,itoa(1567,str,10));
212 : : printf("Base: %d\t\tConverted String: %s\n",2,itoa(1567,str,2));
213 : : printf("Base: %d\t\tConverted String: %s\n",8,itoa(1567,str,8));
214 : : printf("Base: %d\tConverted String: %s\n",16,itoa(1567,str,16));
215 : :
216 : : printf("\n=== Invalid base handling ===\n");
217 : : char errbuf[4];
218 : : char *ret = NULL;
219 : :
220 : : errno = 0;
221 : : ret = itoa(123,errbuf,0);
222 : : printf("Base 0 result: '%s', errno: %d\n",ret ? ret : "NULL",errno);
223 : :
224 : : errno = 0;
225 : : ret = itoa(123,errbuf,1);
226 : : printf("Base 1 result: '%s', errno: %d\n",ret ? ret : "NULL",errno);
227 : :
228 : : errno = 0;
229 : : ret = itoa(123,errbuf,37);
230 : : printf("Base 37 result: '%s', errno: %d\n",ret ? ret : "NULL",errno);
231 : :
232 : : printf("\n=== NULL buffer handling ===\n");
233 : : errno = 0;
234 : : ret = itoa(123,NULL,10);
235 : : printf("NULL buffer result: %s, errno: %d\n",ret ? "non-NULL" : "NULL",errno);
236 : : }
237 : :
238 : : /**
239 : : * @brief Test program for itoa function
240 : : *
241 : : * @note Tests edge cases and different bases with special focus on
242 : : * negative numbers and MIN/MAX integer values
243 : : */
244 : : int main(void)
245 : : {
246 : : test_itoa();
247 : :
248 : : return 0; // Success
249 : : }
250 : : #endif
|