In said:
I will check a String which should contain a HEX value.
I know that strtol is the right function for this job.
But what happens when I will check a hex string with 8 bytes?
That I can check that the string is correct i know.
long value;
char src[]="0x1234567812345678";
char *err;
value = strtol(src,&err, 16);
if (*err != 0x00)
return -1; /*FEHLER*/
The value is not 0x12345678 but I know it is right spelled.
Is that C89 standard or only on my compiler/OS (VC6, Windows) ?
It is C89, but your test is incorrect, as "0x1234567812345678" is of
the expected form in its entirety and there is no final string, so err
is guaranteed to point to the terminating null character:
fangorn:~/tmp 756> cat test.c
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <limits.h>
int main()
{
long value;
char src[]="0x1234567812345678";
char *err;
errno = 0;
value = strtol(src, &err, 16);
perror("strtol");
printf("%ld %ld\n", value, LONG_MAX);
printf("%d\n", *err);
return 0;
}
fangorn:~/tmp 757> gcc test.c
fangorn:~/tmp 758> ./a.out
strtol: Numerical result out of range
2147483647 2147483647
0
Which is exactly as documented: value is set to LONG_MAX, errno is set
to ERANGE and err points to the terminating null character. Of course,
the result would be different on a machine with 64-bit long's.
It is a real PITA to perform error checking correctly after a strtol
call:
errno = 0;
value = strtol(src, &err, 16);
if (err == src) /* complete garbage input */ ;
if (*err != 0) /* trailing garbage */ ;
if ((value == LONG_MAX || value == LONG_MIN) && errno == ERANGE)
/* overflow */;
/* value contains the result of a successful conversion */ ;
Depending on the application, the case of trailing garbage may not be
considered an error.
Is there a way to get the right value of the beginning of the string,
up to the sizeof(long) ?
Yes. The easy way is to insert a null character at the right place in
the input string. The hard way (when it is not guaranteed that the
input string can be modified) is to generate a sscanf format specifying
the maximum number of characters that should be converted and use it in
an sscanf call.
The hardest part is to compute the number of characters without
making *any* assumptions. sizeof(long) * 2 + 2 assumes an 8-bit byte
(and no padding bits). sizeof(long) * CHAR_BIT / 4 + 2 assumes a CHAR_BIT
that is a multiple of 4 and no padding bits in the representation. So,
you really have to start by "dissecting" LONG_MAX... And the easiest
way of doing it is:
char buff[sizeof(long) * CHAR_BIT / 3 + 2];
sprintf(buff, "%lx", (unsigned long)LONG_MAX);
Now, strlen(buff) + 2 is the bullet-proof solution to our problem.
The C99 snprintf removes the need for allocating buff, but reduces the
code portability (the SUS2 version of snprintf is useless for our purpose
and many C89 implementations don't provide snprintf at all).
Dan