How to convert program parameter from argv to int64_t? atoi() is suitable only for 32 bit integers.
There are a few ways to do it:
strtoll(str, NULL, 10);
This is POSIX C99 compliant.
you can also use strtoimax; which has the following prototype:
strtoimax(const char *str, char **endptr, int base);
This is nice because it will always work with the local intmax_t ... This is C99 and you need to include <inttypes.h>
A C99 conforming attempt.
[edit] employed #R. correction
// Note: Typical values of SCNd64 include "lld" and "ld".
#include <inttypes.h>
#include <stdio.h>
int64_t S64(const char *s) {
int64_t i;
char c ;
int scanned = sscanf(s, "%" SCNd64 "%c", &i, &c);
if (scanned == 1) return i;
if (scanned > 1) {
// TBD about extra data found
return i;
}
// TBD failed to scan;
return 0;
}
int main(int argc, char *argv[]) {
if (argc > 1) {
int64_t i = S64(argv[1]);
printf("%" SCNd64 "\n", i);
}
return 0;
}
Users coming from a web search should also consider std::stoll.
It doesn't strictly answer this original question efficiently for a const char* but many users will have a std::string anyways. If you don't care about efficiency you should get an implicit conversion (based on the user-defined conversion using the single-argument std::string constructor) to std::string even if you have a const char*.
It's simpler than std::strtoll which will always require 3 arguments.
It should throw if the input is not a number, but see these comments.
strtoll converts it to a long long which is usually a 64-bit int.
Doing this 100% portably is a little bit tricky. long long is required to be at least 64 bits, but need not necessarily be twos complement, so it might not be able to represent -0x7fffffffffffffff-1, and thus using strtoll could have a broken corner case. The same issue applies to strtoimax. What you could do instead is consume leading space (if you want to allow leading space) and check for the sign first, then use strtoull or strtoumax, either of which is required to support values up to the full positive range of int64_t. You can then apply the sign:
unsigned long long x = strtoull(s, 0, 0);
if (x > INT64_MAX || ...) goto error;
int64_t y = negative ? -(x-1)-1 : x;
This logic is written to avoid all overflow cases.
How to convert string to int64_t?
The simplest
#include <stdlib.h>
int64_t value = atoll(some_string); // Lacks error checking. UB on overflow.
Better
long long v = strtoll(s, NULL, 0); // No reported errors, well defined on overflow.
Robust: Create a helper function to detect all problems.
#include <stdbool.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
// Return error flag
bool my_strtoi64(int64_t *value, const char *s) {
// Maybe add a s==NULL, value==NULL checks.
char *endptr;
errno = 0;
long long v = strtoll(s, &endptr, 0);
// Optional code for future growth of `long long`
#if LLONG_MIN < INT64_MIN || LLONG_MAX > INT64_MAX
if (v < INT64_MIN) {
v = INT64_MIN;
errno = ERANGE;
} else if (v > INT64_MAX) {
v = INT64_MAX;
errno = ERANGE;
#endif
*value = (int64_t) v;
if (s == endptr) { // No conversion, v is 0
return true;
}
if (errno == ERANGE) { // Out of range
return true;
}
if (errno) { // Additional implementations specific errors
return true;
}
while (isspace(*(unsigned char* )endptr)) { // skip trailing white-space
endptr++;
}
if (*endptr) { // Non-numeric trailing text
return true;
}
return false; // no error
}
This worked for me with a different int64 type, and I like the clean C++ style:
std::istringstream iss(argv[i]);
int64_t i64;
iss >> i64;
You may get an compile error: operartor<<... is not defined.
And I don't know what happens, if argv[i] contains "HALLO".
Related
I want to convert a string (guaranteed to consist only of digits) to a 32-bit int. I know of strtol and strtoimax, but these seem to return 64-bit ints.
This is how I'm currently doing it:
#include <errno.h>
#include <inttypes.h>
typedef int32_t Int32;
Int32 strToIntValue(char* str) {
char* end;
errno = 0;
int ret = strtoimax(str, &end, 10);
if (errno==ERANGE) {
printf("range error!\n");
return 0;
}
else {
return (Int32)ret;
}
}
The standard C library does not have a strtoint32().
I want to convert a string ... to a 32-bit int.
I know of strtol and strtoimax, but these seem to return 64-bit ints.
There is long strtol() that certainly meets OP's needs. It forms an integer at least 32-bits. Use it and additional tests if needed.
#include <ctype.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
// really no need for this:
// typedef int32_t Int32;
// Int32 strToIntValue(char* str) {
int32_t strToIntValue(const char* str) {
char* end;
errno = 0;
long num = strtol(str, &end, 10);
if (num == end) {
printf("No conversion error!\n");
return 0;
}
#if LONG_MAX > INT32_MAX
if (num > INT32_MAX) {
num = INT32_MAX;
errno = ERANGE;
}
#endif
#if LONG_MIN < INT32_MIN
if (num < INT32_MIN) {
num = INT32_MIN;
errno = ERANGE;
}
#endif
if (errno==ERANGE) {
printf("range error!\n");
return 0;
}
// Maybe check for trailing non-white space?
while (isspace((unsigned char) *end) {
end++;
}
if (*end) {
printf("Trailing junk!\n");
return 0;
}
// else {
return (int32_t) num;
//}
}
Consider printing error output to stderr rather than stdout.
// printf("range error!\n");
fprintf(stderr, "range error!\n");
See Why is there no strtoi in stdlib.h? for more ideas.
Is there a function to convert an IPv4 address in dotted decimal notation (e.g., "192.168.0.1") into a decimal value?
There are several questions similar to this, but all are looking for or have answers that involve writing a function to solve the answer. I'm looking for an existing function in a library.
The C standard library doesn't have such a function. It's simple enough that this shouldn't be a problem. Here's some example code using strtoul() for parsing:
int parseIpv4Address(uint32_t *addr, const char *addrStr)
{
const char *p = addrStr;
char *endp;
unsigned long a = strtoul(p, &endp, 10);
if (*endp != '.') return -1;
unsigned long b = strtoul(p = endp+1, &endp, 10);
if (*endp != '.') return -1;
unsigned long c = strtoul(p = endp+1, &endp, 10);
if (*endp != '.') return -1;
unsigned long d = strtoul(p = endp+1, &endp, 10);
if (*endp) return -1;
*addr = (uint32_t) ((a << 24) | (b << 16) | (c << 8) | d);
return 0;
}
as unsigned long must have at least 32 value bits, there's no special care (casting) needed for the shifts here.
It doesn't validate the range of the individual parts, if you need this, you should be able to add it without problems.
You could use something like inet_pton which is pretty straight forward to use as you can see from the example code below.
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(void)
{
struct in_addr result;
if(inet_pton(AF_INET,"127.0.0.1",&result))
{
printf("%08x\n",result.s_addr);
}
else
{
printf("Failed\n");
}
return(0);
}
The number is in network byte order, but if you want it in host byte order, you can use ntohl to convert it.
It turns out that Winsock 2 provides the inet_addr() function, which simply returns the equivalent decimal value for the address.
#include <stdio.h>
#include <winsock2.h>
int main(void)
{
char* pAddr = "192.168.0.1";
unsigned long value = inet_addr(pAddr);
if (value == INADDR_NONE)
printf("Invalid format of IP address");
else
printf("Decimal representation of %s is: %lu", pAddr, value);
return 0;
}
I have this code to convert an ASCII string to and int, float, or double. However, it prints "42" for all of them. Where did I go wrong? The syntax looks correct, no warnings.
#include <stdlib.h>
int main(void)
{
char *buf1 = "42";
char buf2[] = "69.00";
int i;
double d;
long l;
i = atoi(buf1);
l = atol(buf1);
d = atof(buf2);
printf("%d\t%d\t%d\n", i, l, d);
return 0;
}
First, you should avoid use of the ato* functions (ie: atoi, atof, etc), because there are cases where the conversion failed, and it just returns zero, so you have no way to know if the input was really a string representing zero, or if it was due to a processing error. If you modify the example below, for example, and change buf2 to "z16", you will get a warning you can handle. atoi would not let you know about that error.
Second, your format specifiers are incorrect in your printf call. Your compiler should have generated warnings about this.
Please refer to the example below for a working version that includes conversion error handling. Not that the explicit casting of strtol to (int) in my example does allow for a potential integer overflow. Try making buf1 a large number, and see what happens.
Good luck!
Code Listing
#include <stdio.h> /* printf */
#include <stdlib.h> /* strtox */
#include <errno.h> /* error numbers */
#define BASE (10) /* use decimal */
int main(void) {
char* errCheck;
char *buf1 = "42";
char *buf2 = "16";
char buf3[] = "69.00";
int i;
double d;
long l;
/* Handle conversions and handle errors */
i = (int)strtol(buf1, &errCheck, BASE);
if(errCheck == buf1) {
printf("Conversion error:%s\n",buf1);
return EIO;
}
l = strtol(buf2, &errCheck, BASE);
if(errCheck == buf2) {
printf("Conversion error:%s\n",buf2);
return EIO;
}
d = strtod(buf3, &errCheck);
if(errCheck == buf3) {
printf("Conversion error:%s\n",buf3);
return EIO;
}
printf("%d\t%ld\t%lf\n", i, l, d);
return 0;
}
Change
printf("%d\t%d\t%d\n", i, l, d);
to
printf("%d\t%ld\t%f\n", i, l, d);
Please don't use ato* functions as ato* functions has been deprecated by strto* and should not be used in new code.
The problem with ato* is, if the converted value is out of range it causes undefined behavior.
For more information check here.
Consider the following code:
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h>
int main (void) {
double val;
/* base b = 2; 2^DBL_MANT_DIG */
/* decimal digits log10(2^DBL_MANT_DIG) */
/*const char *str = "9007199254740992";*/
const char *str = "9007199254740993";
errno = 0;
val = strtod(str, NULL);
printf("%d\n", DBL_MANT_DIG );
if (errno == ERANGE) {
printf("error\n");
} else {
printf("%f\n", val);
}
return 0;
}
This returns:
53
9007199254740992.000000
Since str has a string number that has more significant digits than the my machine can handle, how does one use DBL_MANT_DIG or the log10(2^DBL_MANT_DIG) version of it to check that the result of val is correct?
You don't use those to check that the conversion is exact.
Here's one way of how to do it.
Another way is to find out how many decimal digits after the decimal point are there in the resultant double, do sprintf() using that as the precision and compare its output with the original string.
i'm looking for the standard functions to convert a string to an stdint.h integer, like
int i = atoi("123");
unsigned long ul = strtoul("123", NULL, 10);
uint32_t n = mysteryfunction("123"); // <-- ???
There are two general options: strto[iu]max followed by a check to see if the value fits in the smaller type, or switch to sscanf. The C standard defines an entire family of macros in <inttypes.h> that expand to the appropriate conversion specifier for the <stdint.h> types. Example for uint32_t:
#include <inttypes.h>
#include <stdio.h>
int main()
{
uint32_t n;
sscanf("123", "%"SCNu32, &n);
printf("%"PRIu32"\n", n);
return 0;
}
(In the case of uint32_t, strtoul + overflow check would also work for uint32_t because unsigned long is at least 32 bits wide. It wouldn't reliably work for uint_least32_t, uint_fast32_t, uint64_t etc.)
Edit: as Jens Gustedt notes below, this doesn't offer the full flexibility of strtoul in that you can't specify the base. However, base 8 and base 16 are still possible to obtain with SCNo32 and SCNx32, respectively.
Since your question concerns unsigned integers the overflow check is simple. With a little helper function
inline
unsigned long long
strtoullMax(const char *nptr,
char **endptr,
int base,
unsigned long long maxval) {
unsigned long long ret = strtoll(nptr, endptr, base);
if (ret > maxval) {
ret = maxval;
errrno = ERANGE;
} else {
if (ret == ULLONG_MAX && errno == ERANGE)
ret = maxval;
}
return ret;
}
you easily can define macros that do the trick for any type you are interested in
#define strtou32(NPTR, ENDPTR, BASE) \
strtoullMax(NPTR, ENDPTR, BASE, (uint32_t)-1)
#define strtou32f(NPTR, ENDPTR, BASE) \
strtoullMax(NPTR, ENDPTR, BASE, (uint_fast32_t)-1)
#define strtou32l(NPTR, ENDPTR, BASE) \
strtoullMax(NPTR, ENDPTR, BASE, (uint_least32_t)-1)