I need help

S

Seebs

But do any of them make ptrdiff_t (or any other predefined typedef)
wider than long? If not, then using "%ld" and a cast to long is
enough for this particular case. (And even if ptrdiff_t is wider
than long, it's only a problem if the actual value being printed
exceeds LONG_MAX.)

I'm not sure. I think there is probably at least one with 64-bit pointers
and 32-bit longs.

Ah, well. I don't actually care anymore; I just ignore implementations which
don't have long long, snprintf, and designated initializers. For the most
part this works out.

-s
 
S

sandeep

Keith said:
But do any of them make ptrdiff_t (or any other predefined typedef)
wider than long? If not, then using "%ld" and a cast to long is enough
for this particular case. (And even if ptrdiff_t is wider than long,
it's only a problem if the actual value being printed exceeds LONG_MAX.)

If this is a risk, it would be better to cast to (unsigned long int):
even if the answer was wrong at least there would be no danger of
triggering an undefined behavior by overflow.

This code would be even safer:
ptrdiff_t pd=space - karmarkar;
if(pd<=ULONG_MAX) printf("First space is at position %lu\n",(unsigned
long int)pd);
else printf("First space is at position NaN\nWarning overflow error
detected, please update your C compiler");

Even better else part (in pseudocode):

else {
char* s=karmarkar;
bignum n=new_bignum(0);
while(*s++!=' ')add_bignum(n,n,1);
print_bignum("First space is at position ",n);
}
 
B

Ben Bacarisse

Keith Thompson said:
Unless that assumption leads you to expect warnings from the compiler if
you try to modify it.

The best approach is to add const qualifiers to the declarations:

const char *string = "Simulated Annealing = 12847369";
const char *value = strchr(string, '=');

But again, the compiler won't warn you if you omit the "const".

In the non-standard but useful category... you can get gcc to warn
about this by setting -Wwrite-strings. It makes gcc non-conforming
although in such un-important and, as far as I know, safe corner cases
that I have it on all the time.

One such corner case is

int f(const char (*p)[2]) { return **p; }

where a call such as f(&"*") requires a diagnostic in standard C
(despite being const safe). By making string literals (well, the arrays
that they give rise to) have const elements, -Wwrite-strings suppresses
the required diagnostic.
 
B

Ben Bacarisse

sandeep said:
If this is a risk, it would be better to cast to (unsigned long int):
even if the answer was wrong at least there would be no danger of
triggering an undefined behavior by overflow.

I'd say it's a bad idea. ptrdiff_t is signed so converting it to an
unsigned type for printing will produce unexpected results.

BTW, the conversions don't overflow. In particular, the behaviour is
implementation defined, not undefined; though the difference is slight
in portable code.

<snip>
 
S

Shao Miller

One such corner case is

int f(const char (*p)[2]) { return **p; }

where a call such as f(&"*") requires a diagnostic in standard C
(despite being const safe). By making string literals (well, the arrays
that they give rise to) have const elements, -Wwrite-strings suppresses
the required diagnostic.

Speaking of which, does anyone have any clue as to the rationale behind
why, in:

int main(void) {
char c = 'C';
char * cp = &c;
const char * ccp = &c;
char ** cpp = &cp;
#ifdef NOPE
const char ** ccpp = &cp;
#endif
const char ** ccpp = &ccp;

return 0;
}

we are not permitted to (in a standard sense) "suddenly" 'const'-qualify
the doubly-pointed-to type? It would appear that 6.7.3p9 prevents us
from having compatible types there, and I could understand not wanting
to allow for the _removal_ of 'const' qualification, but couldn't it be
helpful to add it?

Is it for symmetry? Is it because the rules might be too complicated? :)
 
S

Shao Miller

Oops. I'm adding a [hopefully] more meaningful subject.

One such corner case is

int f(const char (*p)[2]) { return **p; }

where a call such as f(&"*") requires a diagnostic in standard C
(despite being const safe). By making string literals (well, the arrays
that they give rise to) have const elements, -Wwrite-strings suppresses
the required diagnostic.

Speaking of which, does anyone have any clue as to the rationale behind
why, in:

int main(void) {
char c = 'C';
char * cp = &c;
const char * ccp = &c;
char ** cpp = &cp;
#ifdef NOPE
const char ** ccpp = &cp;
#endif
const char ** ccpp = &ccp;

return 0;
}

we are not permitted to (in a standard sense) "suddenly" 'const'-qualify
the doubly-pointed-to type? It would appear that 6.7.3p9 prevents us
from having compatible types there, and I could understand not wanting
to allow for the _removal_ of 'const' qualification, but couldn't it be
helpful to add it?

Is it for symmetry? Is it because the rules might be too complicated? :)
 
H

Heikki Kallasjoki

If the conversion from "char **" to "const char **" were allowed without
a cast, the following would be legal:

const char c = 'A';
char *cp = NULL;
const char **ccpp = &cp; /* (1) */
*ccpp = &c; /* (2) */
*cp = 'B'; /* (3) */

Here line (1) converts a char ** to const char ** and normally requires a
cast. Line (2) is legal (ccpp is const char **, so *cpp is const char *,
and that can be set to point to a "const char" without problems.
Unfortunately that has set our char *cp to point to a const char without
casts, and line (3) then silently modifies a const object.

Converting char ** to const char * const* shouls be safe, though.
(Disclaimer: just a gut feeling.)
 
I

Ike Naar

Speaking of which, does anyone have any clue as to the rationale behind
why, in:

int main(void) {
char c = 'C';
char * cp = &c;
const char * ccp = &c;
char ** cpp = &cp;
#ifdef NOPE
const char ** ccpp = &cp;
#endif
const char ** ccpp = &ccp;

return 0;
}

we are not permitted to (in a standard sense) "suddenly" 'const'-qualify
the doubly-pointed-to type? It would appear that 6.7.3p9 prevents us
from having compatible types there, and I could understand not wanting
to allow for the _removal_ of 'const' qualification, but couldn't it be
helpful to add it?

Is it for symmetry? Is it because the rules might be too complicated? :)

Have you read http://c-faq.com/ansi/constmismatch.html ?
 
S

Shao Miller

If the conversion from "char **" to "const char **" were allowed without
a cast, the following would be legal:
[...]

Realized a little too late that this is actually a FAQ, with

http://c-faq.com/ansi/constmismatch.html

having a pretty much identical explanation. Oh well, reinventing the
wheel has a long historical tradition...

Excellent explanation; thanks. I guess that's why it's an FAQ... :)

Of course, there's still type punning and 'void *':

int main(void) {
const char c = 'x';
char *p1;
void *vp = &p1;
const char **p2 = vp;
*p2 = &c;
*p1 = 'X';
return 0;
}

Have a pleasant day.
 
T

Tim Rentsch

Seebs said:
C90 doesn't have a printf conversion specifier for ptrdiff_t, but
converting to long should be enough; ptrdiff_t is a typedef for a
signed integer type, and C90 has no predefined signed type wider
than long.

Unfortunately, nearly every implementation now in use which is being used
in "C90" mode actually has "long long". [snip]

If it's actually conforming to C90 then 'long long'
requires a diagnostic, yes?
 
S

Seebs

Seebs said:
C90 doesn't have a printf conversion specifier for ptrdiff_t, but
converting to long should be enough; ptrdiff_t is a typedef for a
signed integer type, and C90 has no predefined signed type wider
than long.
Unfortunately, nearly every implementation now in use which is being used
in "C90" mode actually has "long long". [snip]
If it's actually conforming to C90 then 'long long'
requires a diagnostic, yes?

Probably, but I've yet to encounter a compiler which is pedantic about such
things in its default mode...

-s
 
K

Keith Thompson

Seebs said:
Seebs said:
C90 doesn't have a printf conversion specifier for ptrdiff_t, but
converting to long should be enough; ptrdiff_t is a typedef for a
signed integer type, and C90 has no predefined signed type wider
than long.
Unfortunately, nearly every implementation now in use which is being used
in "C90" mode actually has "long long". [snip]
If it's actually conforming to C90 then 'long long'
requires a diagnostic, yes?

Probably, but I've yet to encounter a compiler which is pedantic about such
things in its default mode...

I've yet to encounter a C compiler that conforms to *any* standard in
its default mode. (Disclaimer: There are plenty of C compilers I
haven't encountered.)
 
S

Seebs

I've yet to encounter a C compiler that conforms to *any* standard in
its default mode. (Disclaimer: There are plenty of C compilers I
haven't encountered.)

You know, I was going to agree, but then I realized I was thinking too
narrowly; I was thinking only of *C* standards. I am pretty sure there
is at least one compiler which complies with at least one standard.

Or would if the person whose standards were in question were sufficiently
drunk, anyway.

-s
 
T

Tim Rentsch

Seebs said:
Seebs said:
C90 doesn't have a printf conversion specifier for ptrdiff_t, but
converting to long should be enough; ptrdiff_t is a typedef for a
signed integer type, and C90 has no predefined signed type wider
than long.
Unfortunately, nearly every implementation now in use which is being used
in "C90" mode actually has "long long". [snip]
If it's actually conforming to C90 then 'long long'
requires a diagnostic, yes?

Probably, but I've yet to encounter a compiler which is pedantic about such
things in its default mode...

You said C90 mode, not default mode. Obviously there
is no point in talking about conformance if the mode
under consideration isn't supposed to be C90 compliant.
 
D

David Thompson

I'd say it's a bad idea. ptrdiff_t is signed so converting it to an
unsigned type for printing will produce unexpected results.
In general it can, but in many situations including the one upthread
you know the value is nonnegative; then unsigned is 'right'.
 

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
474,091
Messages
2,570,605
Members
47,225
Latest member
DarrinWhit

Latest Threads

Top