Consider scaling the fractional part and adding as suggest by others.
char *s1="100";
char *s2="09";
float f1 = strtof(s1, (void*) NULL);
unsigned n = strlen(s2);
float f2 = strtof(s2, (void*) NULL)/powf(10, n);
return f1 + f2;
This is usually sufficient, yet to dig a bit deeper.
strtof(s2, (void*) NULL)/powf(10, n); incurs a rounding with the division as the quotient, a fraction, is rarely exactly representable as a binary32. Then the addition f1 + f2 may incur another rounding. The sum is sometimes then not the best float answer due to double rounding.
To greatly reduce the chance of double rounding, code can easily use higher precision like double.
float f1 = strtof(s1, (void*) NULL);
unsigned n = strlen(s2);
double f2 = strtod(s2, (void*) NULL)/pow(10, n); // use higher precision
return f1 + f2;
Alternatively code may avoid wider FP math and use exact integer math first to combine the values and then divide, incurring only 1 rounding. This will make for a more accurate answer once in a while.
long l1 = strtol(s1, (void*) NULL, 10);
long l2 = strtol(s2, (void*) NULL, 10);
unsigned n = strlen(s2);
long p10 = pow10(n); // Trivial user TBD code
long sum = l1*p10 + l2; // Exact unless `long` overflow
return 1.0f*sum/p10; // `float` conversion exact for value up to about 1/FLT_EPSILON
The above works well if s1 is negative. Also OK with s2 as a negative aside from more code needed to extract the digit width than strlen(s2).
Else it is hard to beat a string concatenation and convert. I recommend float strof() over double atof() as 1) atof() lacks defined behavior on overflow, 2) atof() uses double math, which may be slower.
size_t l1 = strlen(s1);
size_t l2 = strlen(s1);
char buffer[l1 + 1 + l2 + 1]; // Or use a fixed wide buffer with test to insure fit
strcpy(buffer, s1);
buffer[l1] = '.';
strcpy(buffer + l1 + 1, s1);
return strtof(buffer, (void *) NULL);