Are suffixes allowed on expressions?
For example, is the following allowed:
#define SECONDS_PER_YEAR (60 * 60 * 365) UL
I found this in a C test at http://www.embedded.com/2000/0005/0005feat2.htm
,
however, I am not able to compile when using this macro (or just the
expression "a = (60 * 60 * 365) UL;").
Where in the standard does it say that it is allowed/not allowed?
It would also be interesting to hear if there are any faults in the
other questions and answers in the test.
BRs!
It should be:
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365) UL
>
> I found this in a C test athttp://www.embedded.com/2000/0005/0005feat2.htm
> ,
> however, I am not able to compile when using this macro (or just the
> expression "a = (60 * 60 * 365) UL;").
It should be:
(or just the expression statement "a = (60 * 60 * 24 * 365) UL;")
> Are suffixes allowed on expressions?
No. The suffixes that you are talking about are allowed only on
integer and floating-point constants.
> For example, is the following allowed:
>
> #define SECONDS_PER_YEAR (60 * 60 * 365) UL
No. To get the apparently intended effect, you can write
#define SECONDS_PER_YEAR (60UL * 60 * 365)
or
#define SECONDS_PER_YEAR (unsigned long int) (60 * 60 * 365)
--
"All code should be deliberately written for the purposes of instruction.
If your code isn't readable, it isn't finished yet."
--Richard Heathfield
> To get the apparently intended effect, you can write
> #define SECONDS_PER_YEAR (60UL * 60 * 365)
> or
> #define SECONDS_PER_YEAR (unsigned long int) (60 * 60 * 365)
Oh, and to get the apparently intended value, you need to
multiply by an additional factor of 24.
--
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
> dspfun <dsp...@hotmail.com> writes:
>
>> For example, is the following allowed:
>>
>> #define SECONDS_PER_YEAR (60 * 60 * 365) UL
>
> No. To get the apparently intended effect, you can write
> #define SECONDS_PER_YEAR (60UL * 60 * 365)
> or
> #define SECONDS_PER_YEAR (unsigned long int) (60 * 60 * 365)
The latter can, as I am sure you know, overflow. Since the quiz was
on a site that referenced embedded systems, it would be safer to
assume a minimal max int (if you see what I mean).
To the OP: to illustrate using a cast (which *can* be used in
expressions unlike suffixes) you could write:
#define SECONDS_PER_YEAR ((unsigned long int)60 * 60 * 365)
* is left-associative so all the multiplications must produce unsigned
long int results.
--
Ben.
No (unless the expression happens to be an integer constant).
> For example, is the following allowed:
>
> #define SECONDS_PER_YEAR (60 * 60 * 365) UL
Nope.
> I found this in a C test at
> http://www.embedded.com/2000/0005/0005feat2.htm , however, I am not
> able to compile when using this macro (or just the expression "a =
> (60 * 60 * 365) UL;").
>
> Where in the standard does it say that it is allowed/not allowed?
Suffixes such as UL are described in C99 6.4.4.1, "Integer constants"
(and similar suffixes are described in 6.4.4.2, "Floating constants").
The fact that they aren't described anywhere else, particularly the
fact that the grammar permits them only in those contexts, implies
that they aren't permitted anywhere else. (There's no need to state
that they're not allowed.)
> It would also be interesting to hear if there are any faults in the
> other questions and answers in the test.
Some of the code layout is messed up, at least in my browser. In some
cases, lines are split before and after '<' characters. I'd guess
this isn't the author's fault.
As you say, he completely messed up on the first question. Failing to
compile code to be used in a published article is a *big* mistake.
In question 8 about the volatile keyword, he says that the variable
can be changed unexpectedly, but he fails to mention that when the
*program* changes a volatile variable, the new value must actually be
stored rather than cached. He covers the implications for reading the
variable, but not for writing it. (The latter is a constraint on the
implementation, not on the programmer, so perhaps that's excusable.)
In question 14, he needlessly casts the result of malloc(). Worse
than that, he's mistaken about the actual point of the question, the
result of malloc(0). He says, or strongly implies, that malloc(0)
always returns a valid (non-null) pointer. In fact, it's
implementation-defined whether malloc(0) returns a null pointer or a
unique non-null pointer.
Question 15 asks which of these is preferred:
#define dPS struct s *
typedef struct s * tPS;
as a way to define an alias for a pointer to type "struct s". Apart
from failing to mention the inadvisability of aliasing a pointer type,
he gets the asnwer right, but his attitude here is odd to the point
of being wrong:
This is a very subtle question, and anyone who gets it right (for
the right reason) is to be congratulated or condemned ("get a
life" springs to mind).
The problem, of course, is with declarations like:
dPS p1, p2;
tPS p3, p4;
But this isn't a remarkably obscure point, as he implies; it's
something that every C programmer should know.
There's a contact address in the article; I'll send him pointers to
your article and my followup.
--
Keith Thompson (The_Other_Keith) <ks...@mib.org>
[...]
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
The e-mail address in the article is obsolete (I think the article is
several years old). I found what appears to be his current address by
searching the embedded.com web site. (I won't post it here; I'm sure
he gets more than enough spam already.)
The second will only work if the expression (60 * 60 * 365) is
within the range of an int. This is doubtful if running on a 16
bit system.
--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee, Frohe Weihnachten
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
--
Posted via a free Usenet account from http://www.teranews.com
---------------
12. What does the following code output and why?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}
Answer:
This question tests whether you understand the integer promotion rules
in C-an area that I find is very poorly understood by many developers.
Anyway, the answer is that this outputs "> 6." The reason for this is
that expressions involving signed and unsigned types have all operands
promoted to unsigned types. Thus ý20 becomes a very large positive
integer and the expression evaluates to greater than 6. This is a very
important point in embedded systems where unsigned data types should
be used frequently (see Reference 2). If you get this one wrong, you
are perilously close to not getting the job.
-------------
> On 2 Jan, 19:07, dspfun <dsp...@hotmail.com> wrote:
>> Hi!
>>
>> Are suffixes allowed on expressions?
>>
>> For example, is the following allowed:
>>
>> #define SECONDS_PER_YEAR (60 * 60 * 365) UL
>
> It should be:
> #define SECONDS_PER_YEAR (60 * 60 * 24 * 365) UL
The result of the above calculation will be out by 86400 seconds this year.
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
This has nothing to do with the representation of the basic types, it
depends only upon the usual arithmetic conversions. While the results
of those conversions vary from implementation to implementation, the
particular values chose for a and b below are guaranteed to produce
the same final results on all conforming implementations of C.
> ---------------
> 12. What does the following code output and why?
>
> void foo(void)
> {
> unsigned int a = 6;
> int b = -20;
> (a+b > 6) ? puts("> 6") : puts("<= 6");
> }
>
> Answer:
> This question tests whether you understand the integer promotion rules
> in C-an area that I find is very poorly understood by many developers.
> Anyway, the answer is that this outputs "> 6." The reason for this is
> that expressions involving signed and unsigned types have all operands
> promoted to unsigned types. ...
Note that this is not the correct rule in C99, though I think it's a
correct statement of the C90 rule. In C99, the signed operand is
converted to the type of the unsigned operand only if the rank of the
unsigned type is greater than or equal to the rank of the signed type.
In this case, that happens to be true.
> ... Thus �20 becomes a very large positive
> integer and the expression evaluates to greater than 6. ...
Specifically, (a+b) has a value of UINT_MAX-13. The value of that sum
depends upon the implementation, since UINT_MAX depends upon the
implementation. However, since UINT_MAX must be at least 65535, that
value is guaranteed to be at least 65522, and therefore greater than
6, and the routine is guaranteed to pass "> 6" to puts().
On the originally referenced web site, the relevant question specified
that leap years are to be ignored. The macro name should have
reflected that fact, though I'm not sure of the best way to do so.
SECONDS_PER_NON_LEAP_YEAR?
Ok, thank you for the explanation! I believe it is the following in
C99 that specifies this (that the result of a+b will be UINT_MAX + 1
-20 + 6 = UINT_MAX-13):
2
Otherwise, if the new type is unsigned, the value is converted by
repeatedly adding or
subtracting one more than the maximum value that can be represented in
the new type
until the value is in the range of the new type.49)
Too long. Try SECS_PER_SQUAT_YR. :-)
The term for a non-leap year is "common year".
> dspfun <dsp...@hotmail.com> writes:
>> Are suffixes allowed on expressions?
>
> No (unless the expression happens to be an integer constant).
The suffix is *part* of the constant. They form one token.
You can't have e.g. `12 UL`.
--
Army1987 (Replace "NOSPAM" with "email")
And SECONDS_PER_YEAR really is equal to (60 * 60 * 24 * 365).
^^^^
--
+----------------------------------------------------------------+
| Charles and Francis Richmond richmond at plano dot net |
+----------------------------------------------------------------+
int const * a const;
The declaration above doesn't compile using gcc.
'const' is a type-qualifier, and therefore a declaration-specifier.
'a' is parsed as a direct-declarator, and therefore as a declarator,
and therefore as an init-declarator-list. 6.7p1 requires that
declarations-specifiers preceed the init-declarator-list, so this is
an incorrect declaration.
Thanks for a great answer!
How did you do the mapping type-qualifier -> declaration-specifier and
direct-declarator -> declarator -> init-declarator-list ?
I found something more suspicuous in the anser to question 2:
"Knowledge of the ternary conditional operator. This operator exists
in C because it allows the compiler to produce more optimal code than
an if-then-else sequence. "
Is this really true?
dspfun wrote:
> On 3 Jan, 21:18, jameskuy...@verizon.net wrote:
> > dspfun wrote:
> > > How about question 7, is it correct (referring to the test in the link
> > > at the top of the thread)? :
> >
> > > int const * a const;
> >
> > > The declaration above doesn't compile using gcc.
> >
> > 'const' is a type-qualifier, and therefore a declaration-specifier.
> > 'a' is parsed as a direct-declarator, and therefore as a declarator,
> > and therefore as an init-declarator-list. 6.7p1 requires that
> > declarations-specifiers preceed the init-declarator-list, so this is
> > an incorrect declaration.
>
> Thanks for a great answer!
>
> How did you do the mapping type-qualifier -> declaration-specifier and
This is just a matter of reading and correctly interpreting the
productions listed in section 6.7p1.
> direct-declarator -> declarator -> init-declarator-list ?
I left out init-declarator, between the last two items there. See
sections 6.7.5p1 and 6.7p1.
> I found something more suspicuous in the anser to question 2:
>
> "Knowledge of the ternary conditional operator. This operator exists
> in C because it allows the compiler to produce more optimal code than
> an if-then-else sequence. "
>
> Is this really true?
I sincerely doubt that any modern compiler produces different code
depending upon whether if-then-else or ?: is used, and I'm quite sure
that any such minor efficiencies have nothing to do with the reason
why it exists. The ?: operator is syntactic sugar, which makes certain
construct much simpler to write. It's not necessary, but it is
occasionally convenient, and convenience should not be underrated as a
feature of a computer programming language.
> How about question 7, is it correct (referring to the test in the link
> at the top of the thread)? :
>
> int const * a const;
This is probably a typo for:
int const *const a;
although I would write such a declaration as, equivalently:
const int *const a;
--
"If I've told you once, I've told you LLONG_MAX times not to
exaggerate."
--Jack Klein
Ok, if I've understood things correctly in the C standard, this is how
the productions listed in section 6.7p1 should be read (with respect
to the above declaration the above declaration):
6.3.2.1p2: An identifier is a sequence of nondigit characters
(including the underscore _, the lowercase and uppercase Latin
letters, and other characters) and digits, which designates one or
more entities as described in 6.2.1.
Hence, "a" is an identifier.
6.7p6: The declarators contain the identifiers (if any) being
declared.
6.7.5p2:Each declarator declares one identifier, and asserts that when
an operand of the same form as the declarator appears in an
expression, it designates a function or object with the scope, storage
duration, and type indicated by the declaration specifiers.
Hence, "* a" is a declarator.
6.7p1:
init-declarator:
declarator
declarator = initializer
Hence, "* a" is also an init-declarator.
6.7p1:
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
Hence, "a *" is also the init-declarator-list.
--------------------------------------------------
6.7.3p1:
type-qualifier:
const
restrict
volatile
Hence, "const" is a type-qualifier.
6.7p1:
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
Hence, "const" is a declaration-specifier.
--------------------------------------------------
6.7p1:
declaration:
declaration-specifiers init-declarator-listopt ;
Hence, "const" has to preceed "* a"
Here is the question:
-------------------------------------
Accessing fixed memory locations
10. Embedded systems are often characterized by requiring the
programmer to access a specific memory location. On a certain project
it is required to set an integer variable at the absolute address
0x67a9 to the value 0xaa55. The compiler is a pure ANSI compiler.
Write code to accomplish this task.
This problem tests whether you know that it is legal to typecast an
integer to a pointer in order to access an absolute location. The
exact syntax varies depending upon one's style. However, I would
typically be looking for something like this:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
A more obscure approach is:
*(int * const)(0x67a9) = 0xaa55;
Even if your taste runs more to the second solution, I suggest the
first solution when you are in an interview situation.
----------------------------
>>This problem tests whether you know that it is legal to typecast an
>>integer to a pointer in order to access an absolute location.
C does permit an integer to be typecast to a pointer, but it says that
the result is implementation dependant, even putting aside alignment
issues. The resulting pointer might not be usable for any accesses no
matter what value was cast; the resulting pointer might be usable for
an access to an address that doesn't look anything like the integer;
the resulting pointer might be usable for an access into the program's
virtual memory rather than to an absolute address; the resulting
pointer might be usable for an access to an absolute address; the
ability to use the pointer to access an absolute address might depend
upon the privileges the program has been granted; the ability to use
the pointer to access an absolute address might depend upon the exact
absolute address and whether the system has been configured to allow
user programs to access that specific address.
So, just as you say, the result is indeed system specific.
--
"I will speculate that [...] applications [...] could actually see a
performance boost for most users by going dual-core [...] because it
is running the adware and spyware that [...] are otherwise slowing
down the single CPU that user has today" -- Herb Sutter
Ok, thank you for your answer!
Could you give a pointer to where in the standard it says that an
integer (constant) can be typecasted to a pointer and the result is
implementation dependent?
>Could you give a pointer to where in the standard it says that an
>integer (constant) can be typecasted to a pointer and the result is
>implementation dependent?
>
C89 3.3.4 Cast Operators
An abitrary integer may be converted to a pointer. The result
is implementation-defined. [45]
{footnote} [45] The mapping functions for converting a pointer to
an integer or an integer to a pointer are intended to be
consistent with the addressing structure of the execution
environment.
--
"Any sufficiently advanced bug is indistinguishable from a feature."
-- Rich Kulawiec
Thank you, is the same valid for C99?
Essentially. Section 6.3.2.3 says:
"An integer may be converted to any pointer type. Except as previously
specified, the
result is implementation-defined, might not be properly aligned, and
might not point to an
entity of the referenced type."
The footnote is the same.
> A more obscure approach is:
> *(int * const)(0x67a9) = 0xaa55;
It's *extremely* obscure why one would give an rvalue a const
type.
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
With the author's permission, I'm posting his response to my e-mail.
I've rearranged the text to put his response after mine, and I've
added "|| " before my message and "| " before his response.
|| Hello. Somebody just posted a pointer to your article "A 'C'
|| Test: The 0x10 Best Questions for Would-be Embedded Programmers",
|| <http://www.embedded.com/2000/0005/0005feat2.htm> to the comp.lang.c
|| Usenet newsgroup, pointing out a serious error in the first question.
|| I've posted a followup. You can read the orginal post at
||
|| http://groups.google.com/group/comp.lang.c/msg/131a36cd616fa566
||
|| and my followup at
||
|| http://groups.google.com/group/comp.lang.c/msg/7029524f1567fe2f
||
|| There have been several other responses in the thread; persuading
|| Google Groups to show the tree of responses is left as an exercise.
||
|| (My first attempt to send you this message bounced because I had the
|| wrong e-mail address. I think the article is fairly old; the URL
|| implies that it's from the year 2000 -- though "curl --head" says
|| the "0005feat2.htm" was last modified Tue, Jan 27 2099 23:59:59 GMT.
|| Somebody might want to look into the settings on your web server.)
|
| Hi Keith:
|
| I took a look at your post. The UL outside the brackets was a typesetting
| error that wasn't caught on the proof read. Incidentally, a far more
| interesting thing to note is whether the UL actually buys you anything. I
| think it does, but I've had others that disagree with me.
|
| Regarding Q8 - I think you missed my point. In my experience less than 10%
| of C programmers know what volatile is, let alone all its subtleties. Given
| that this was a C *test*, the objective was more to test than to teach. In
| short if an embedded programmer doesn't know what volatile is, or has a hazy
| knowledge, then they are useless.
|
| In question 14. Regarding the needless cast to the result of malloc(). I
| personally am very cautious with implicit casts. Thus it's my style to
| always cast the result of malloc and other such functions. Having said that,
| I can't remember the last time I used malloc() since heap fragmentation is
| not normally something I can tolerate.
|
| Sticking with question 14, you are correct that I was wrong about the
| results of malloc(0). I erroneously thought that malloc(0) always returned a
| valid pointer. Having said that, the main point of the question was to
| determine which of the two "camps" you fall in to.
|
| Camp "1": The programmer is king. I'm smarter than the compiler, so if I
| want to do something like call malloc(0) then I expect a valid pointer.
|
| Camp "2": I'm human and make stupid mistakes. I'd really like the compiler
| to remind me when I do something stupid, or at least suspicious.
|
| BTW, if you genuinely knew that the results of malloc(0) was implementation
| dependent, then I suspect that you are a compiler writer, or you spend more
| time reading compiler manuals than I do, since I think you'd agree it's a
| pretty obscure point.
|
| I'm sorry that my attitude / tone for Q15 offended you. The article was
| supposed to be light hearted, while at the same time making some good
| points. As to your claim that the solution to Q15 is something every C
| programmer should know - I agree. However, I think you'll find that >95%
| can't answer this question correctly. If you're in an organization with many
| programmers, I'd be interested to see how many of them can answer the
| question correctly. (BTW, the folks that hang out on the comp.lang.c Usenet
| newsgroup probably aren't representative of the programming population.)
|
| Incidentally, what I have found with Q15 is that the better candidates
| instinctively know that the typedef is the better solution - but without
| being able to quite articulate why.
|
| Thanks for writing.
You can answer this sort of question more easily yourself, with a
text version of the C standard and grep. grep is available
everywhere. For the text version I suggest N869_txt.bz2, which is
a bzip2 compressed version of N869, and is available at:
<http://cbfalconer.home.att.net/download/>
--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.
n1256.pdf, available at
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf>,
is more current. It's PDF rather than plain text, which may or may
not be a problem.
I'm not convinced that a simple grep would be useful in this case.
For example, the word "typecast" appears nowhere in the standard.
What would you grep for?
I just found the relevant section in n1256.pdf by traversing the
table of context, which is easy to do in a decent PDF reader:
6 Language
6.3 Conversions
6.3.2 Other operands
6.3.2.3 Pointers
Paragraph 5:
An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined,
might not be correctly aligned, might not point to an entity
of the referenced type, and might be a trap representation.
(The last line of the paragraph has a change bar, which means it
changed post-C99.)
For example, I just entered:
grep -n cast \stds\n869.txt | less
and got a set of roughly 60 lines. This took all of 2 seconds. It
shouldn't take much to hide that output and just save the line
numbers, which can then be used to illuminate all the areas of
interest.
Yeah, but the OP is under the mistaken impression that "typecasting" has
something to do with C, rather than with Hollywood. :-(
It would probably have been useful to have advised him that the word he
was searching for was 'convert'.
--
Mark McIntyre
CLC FAQ <http://c-faq.com/>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>
Can you explain what you mean?
Isn't 0xaa55 the rvalue, 0xaa55 is an integer constant, what is the
obscure thing about that?
> On 4 Jan, 01:46, Ben Pfaff <b...@cs.stanford.edu> wrote:
>> dspfun <dsp...@hotmail.com> writes:
>> > A more obscure approach is:
>> > *(int * const)(0x67a9) = 0xaa55;
>>
>> It's *extremely* obscure why one would give an rvalue a const
>> type.
>
> Can you explain what you mean?
"const" is attached to a type to make objects of that type
non-modifiable. But the result of a cast is never modifiable,
because it is not an lvalue. So the "const" keyword here is
useless.
--
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
If const in the above expression statement is useless, is it also
implementation specific? Does the standard specify it to be useless
(explicitly or implicitly)?
One could imagine a cast like this:
const int * p;
p = (const int *)(0x67a9);
Then the const qualifier is not useless in the cast?
Yes, the standard requires it to be useless:
"The properties associated with qualified types are meaningful only for
expressions that are lvalues."
> One could imagine a cast like this:
>
> const int * p;
> p = (const int *)(0x67a9);
>
> Then the const qualifier is not useless in the cast?
In that cast, the target type is an unqualified pointer. It happens to be
a pointer to a const-qualified int, but that is not relevant to the
discussion.
So, are the following two pointers identical? :
const int * p1;
int * p2;
p1 can be modified to any value, but whichever object p1 addresses can
not be modified (using *p1). It seems as if the const type qualifier
information "follows" p1?
No.
> p1 can be modified to any value, but whichever object p1 addresses can
> not be modified (using *p1). It seems as if the const type qualifier
> information "follows" p1?
Indeed. *p1 is an lvalue of type const int, and for lvalues, type
qualifiers do matter.
So, in the above, is p1 a qualified pointer, and p2 an unqualified
pointer?
No. I already stated in my first message in this subthread that const int
* is an unqualified pointer to a const-qualified int. The const does not
apply to the pointer itself.
const int *p;
p = 0;
If that's valid, p is not const-qualified. That's valid.
I guess the source of my confusion could be exemplified by the
following:
const int *p1;
int *p2;
p1 = (int *)(0x67a9);
p2 = (int *)(0x67a9);
p1 points to an int which is not modifiable while p2 points to an int
which is modifiable. But they both point to the same int.
Thanks for your time and help!!
They both point to the same /memory location/, yes.
But thats not a problem - think of it as similar to file modes. The
'const' qualifier is like opening a readonly file handle. An application
can open two handles on a file, one readonly and the other read/write.
Since p1 is defined as a pointer to a const int, I feel the cast of
0x67a9 should have been to a pointer which points to a const int.
But the cast of 0x67a9 is to a pointer which points to an int, and not
to a const int.
So to me it seems as if the "type" of p1 is slightly different from
the "type" of "(int *) 0x6a70".
Thanks again!
Yes, the types are different. One is 'const int *' the other is 'int
*'. They ('p1' and '(int *)(0x67a9)') are both pointers but to
differently qualified versions of the same type ('int').
Assignment (and also parameter passing) allows qualifiers to be added
to the "pointed to" type. There is a passage in the standard that
specifically states this permission. The reverse is not allowed:
p2 = p1;
after the code you quote is a constraint violation.
--
Ben.
Well, you lied to the compiler... if you want a const int*, tell it
thats what you have !
Also - the assignment adds the constness. RTFS to determine the precise
para that allows this.
There is no connection of any kind between the 'const' in the cast
expression and the fact that 0xaa55 is a constant expression. Whatever
connection you think exists reflects a misunderstanding on your part.
In a pointer declaration, a qualifier such as 'const' that appears
before the '*' qualifies the values that are pointed at. When the
'const' occurs after the '*', it applies to the pointer value itself,
not the pointed-at value.
when the 'const' qualifier applies to an lvalue, it disqualifies the
lvalue from being modifiable. If the operand of an increment or
decrement expression, or the left operand of an assignment is not a
modifiable lvalue, it is a constraint violation. This is the main
purpose of declaring things to be 'const'. It is already a constraint
violation for (int *)(0x67a9) to be in any of those situations, because
it isn't an lvalue, so making it (int * const)(0x67a9) doesn't change
anything. The 'const' is completely pointless in that position.
Using (int const*)(0x67a9) would change things, because in that case
'const' would apply to the pointed-at value, rather than the pointer
value. The effect of using that declaration would be to make the
assignment above a constraint violation.