Portable and ok?

P

pemo

/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}
 
C

Clark S. Cox III

/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}

The only part of that that isn't portable is the attempt to convert
NULL to a char. However, if you were asking about the
("0123456789ABCDEF"[n]) part, that's fine. I would rewrite that
function as:

char itoh(int n)
{
return n < 0 || n > 15 ? 0 : "0123456789ABCDEF"[n];
}
 
A

Antonio Contreras

pemo said:
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}

Why null? Why not return 0?

IIRC NULL is allowed to be defined as (void *) 0, which could cause
problems with your code.
 
S

Skarmander

pemo said:
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}

No. Conversion from NULL to a char is undefined. I recommend returning
'?' instead, or triggering an assertion or other exception mechanism to
handle the problem.

Returning NUL ('\0') is also a possibility, but one I would avoid, since
it would likely lead to mysteriously truncated strings.

S.
 
D

Dick de Boer

pemo said:
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}
For n out of range:
NULL is a pointer, not a char. In this code, the NULL will be converted to a
char, and *if* NULL equals zero, the return value will be zero. If NULL
equals not zero but for instance (void*)-1, the value 255 will be returned.
If the char is unsigned by default (implementation defined), this will never
compare equal with NULL.

So, NOT portable.

DickB
 
C

Chris Dollin

pemo said:
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.

[For NUL read `some sensible error-character`.]

Your description is inconsistent: if the value is in the range
0..15, then there's no need for a NUL error-value; if you need
the NUL error-value, you don't need the restriction 0 - 15.

Since your code handles the general case, I'd suggest

input: an integer N.
return: if 0 <= N <= 15, the corresponding hex character;
otherwise, NUL.
 
M

Martin Ambuhl

pemo wrote:
[Repeated from subject line, where it was wrongly tucked away:
Subject: Portable and ok?]

No, it's not OK. Don't use pointers for integer values even if you have
every reason to think it will work. Why are you avoiding using 0 when
you mean 0?
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
^^^^ 0
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
^^^^ 0
 
F

Flash Gordon

Dick said:
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}

For n out of range:
NULL is a pointer, not a char. In this code, the NULL will be converted to a
char, and *if* NULL equals zero, the return value will be zero. If NULL
equals not zero but for instance (void*)-1,

Highly unlikely. (void*)0 and ((void*)0) are likely, but (void*)-1 is
*very* unlikely. The reason being that (void*)0 is *required* to produce
a null pointer, but (void*)-1 is not.
> the value 255 will be returned.
If the char is unsigned by default (implementation defined), this will never
compare equal with NULL.

If NULL is defined as (void*)anything then the compiler is *required* to
produce a diagnostic because pointers cannot be implicitly converted to
integer types. *If* it produced an executable, which it would not be
required to, then it could return anything it wanted.
So, NOT portable.

True.
 
J

Jordan Abel

Dick said:
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}

For n out of range:
NULL is a pointer, not a char. In this code, the NULL will be converted to a
char, and *if* NULL equals zero, the return value will be zero. If NULL
equals not zero but for instance (void*)-1,

Highly unlikely. (void*)0 and ((void*)0) are likely, but (void*)-1 is
*very* unlikely. The reason being that (void*)0 is *required* to produce
a null pointer, but (void*)-1 is not.

ok, suppose "null pointers are all-bits-1". There's no guarantee that
converting a null pointer back to an int will yield a 0.
 
F

Flash Gordon

Jordan said:
ok, suppose "null pointers are all-bits-1". There's no guarantee that
converting a null pointer back to an int will yield a 0.

Yes, I completely agree.
 
K

Keith Thompson

Jordan Abel said:
Dick said:
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}

For n out of range:
NULL is a pointer, not a char. In this code, the NULL will be
converted to a char, and *if* NULL equals zero, the return value
will be zero. If NULL equals not zero but for instance (void*)-1,

Highly unlikely. (void*)0 and ((void*)0) are likely, but (void*)-1 is
*very* unlikely. The reason being that (void*)0 is *required* to produce
a null pointer, but (void*)-1 is not.

ok, suppose "null pointers are all-bits-1". There's no guarantee that
converting a null pointer back to an int will yield a 0.

Certainly -- but note that the code we're discussing uses a null
pointer constant, not (necessarily) a null pointer. If the
implementation uses all-bits-1 for null pointers, NULL could still be
defined as 0; it would result in all-bits-1 if converted to a pointer
type, but would still act as a plain integer constant 0 if it's not
converted to a pointer type.

On the other hand, if NULL is defined as ((void*)0), it would *still*
result in all-bits-1 if coverted to a pointer type, but it must
trigger a diagnostic if used as above.

Even if an implementation uses something other than all-bits-zero for
null pointers, that doesn't affect the definition of a null pointer
constant (something that exists only in program source), and it's not
likely to affect the definition of NULL.

I think the OP has two problems. First, he's incorrectly assuming
that NULL refers to a null character rather than a null pointer
constant. Second, he's probably using an implementation that defines
NULL as 0, so it isn't catching the error.
 
S

Simon Biber

Martin said:
pemo wrote:
[Repeated from subject line, where it was wrongly tucked away:
Subject: Portable and ok?]

No, it's not OK. Don't use pointers for integer values even if you have
every reason to think it will work. Why are you avoiding using 0 when
you mean 0?

Since the OP doesn't appear to be participating in this thread, allow me
to hazard a guess:

- don't know the difference between a null pointer and a null character

- the teacher said to *never* use literal values

- thought it possible that null may not be zero, better use the macro
to be sure

Unfortunately, in my experience very few teachers accurately teach the
difference between a null pointer, a null pointer constant and a null
character.
 
J

Jordan Abel

- the teacher said to *never* use literal values

- thought it possible that null may not be zero, better use the macro
to be sure

in either of those two cases, the appropriate way would be '\0'
 
K

Keith Thompson

Jordan Abel said:
in either of those two cases, the appropriate way would be '\0'

Um, '\0' is a literal value.

Of course, there's absolutely nothing wrong with using a literal '\0'
where it's appropriate. *If* the teacher said never to use literal
values, it's very bad advice -- but of course we have no direct
evidence that the teacher said so.
 
J

Jordan Abel

Um, '\0' is a literal value.

So is the string he has with the hex digits - there's very little
you can do without literal values of any kind - i think the most
complicated program you can implement is echo.
 
K

Keith Thompson

Jordan Abel said:
So is the string he has with the hex digits - there's very little
you can do without literal values of any kind - i think the most
complicated program you can implement is echo.

Aha, a challenge!

Without using literals, you can easily construct constant expressions
for any integer you like:

static int dummy;
#define ZERO (&dummy!=&dummy)
#define ONE (&dummy==&dummy)
#define TWO (ONE+ONE)
#define THREE (TWO+ONE)
#define FOUR (THREE+ONE)

Character and string literals are a bit more difficult. You can
construct anything you like if you're willing to assume an ASCII
encoding, but that's cheating. I think you can determine the values
of '0' through '9' by looping over the range 0 .. SCHAR_MAX and
checking isdigit(). You can do the same thing for letters by checking
isupper() and islower(); this works for both ASCII and EBCDIC, but not
for any character sets in which the letters aren't in alphabetical
order. (The results won't be constant expressions unless you go to a
*lot* of extra effort.)

fopen() is difficult because the mode argument is usually a string
literal. It doesn't have to be a constant, but I can't think of a
good way to generate an 'r' or 'w' character.

printf(), of course, requires a format string. It can be built up
manually if you can construct the required characters.

Just to be clear (and because I've criticized others for not including
this disclaimer), this is absolutely nothing more than a silly little
intellectual exercise, of no actual use that I can think of. And I
haven't had a homework assignment in decades.
 
J

Jordan Abel

Aha, a challenge!

Without using literals, you can easily construct constant expressions
for any integer you like:

[snip other stuff]

geez - it'd be easier to program in brainf***
 
K

Kenneth Brody

Clark S. Cox III said:
/*
** input: an integer [value]. In the range. 0 - 15.
**
** return: if in range, the character that encodes the value
** passed as a hex char - else - NULL.
*/
char itoh(int n)
{
return n < 0 || n > 15 ? NULL : "0123456789ABCDEF"[n];
}

The only part of that that isn't portable is the attempt to convert
NULL to a char. However, if you were asking about the
("0123456789ABCDEF"[n]) part, that's fine. I would rewrite that
function as:

char itoh(int n)
{
return n < 0 || n > 15 ? 0 : "0123456789ABCDEF"[n];
}

And, for clarity, I would make a minor change:

char itoh(int n)
{
return (n < 0 || n > 15) ? '\0' : "0123456789ABCDEF"[n];
}

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Kenneth Brody

Keith said:
Um, '\0' is a literal value.

Of course, there's absolutely nothing wrong with using a literal '\0'
where it's appropriate. *If* the teacher said never to use literal
values, it's very bad advice -- but of course we have no direct
evidence that the teacher said so.

And if the teacher really said never use literal values, then you can't
use the literal "0123456789ABCDEF", either. In fact, you couldn't even
use "%x" to pass to sprintf.

Unless you're allow to use

#define MyHexString "0123456789ABCDEF"

But, I guess this depends on how picky the teacher is.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
T

tedu

Keith said:
fopen() is difficult because the mode argument is usually a string
literal. It doesn't have to be a constant, but I can't think of a
good way to generate an 'r' or 'w' character.

const char *r() { return __func__; }
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,229
Latest member
GloryAngul

Latest Threads

Top