the same memory location can have different values

  • Thread starter Floare Augustin Theodor
  • Start date
A

Alf P. Steinbach

* James Kanze:
It's obviously a question of how you define /, but if you are
defining it as a closed operation over the set of reals, then
division by zero is excluded (or you can't define it).

Yes.

In the end it comes down to practical utility.

As I mentioned, in programming x/0 has some very practical utility (for updating
products of sets of numbers), whereas e.g. the number system extension (I'm not
sure of the formal terminology, but I think you'll get my drift) that you get by
postulating a non-complex-number entitity k where k*k = +1, possibly (I dunno) a
hyperbolic version of complex i*i = -1, is AFAIK without any practical utility
whatsoever. But it's fun to think about such things, a little out of the box so
to speak, and sometimes they turn out to have practical value. :)


Cheers,

- Alf
 
F

Floare Augustin Theodor

This is the exact quote from Herbert Schildt ("C The Complete
Reference"):

"You can also use const to verify that your program does not modify a
variable. Remember, a variable of type const can be modified by
something outside your program. For example, a hardware device may set
its value. However, by declaring a variable as const, you can prove
that any changes to that variable occur because of external events."
 
F

Floare Augustin Theodor

By having a variable of type const, initialized with a value, the
compiler is likely to replace every instance of the variable with its
initial value. To impede this optimization of compiler, the variable
will be defined with type const and type volatile. In this case every
instance of the variable will access the memory location of the
variable.

One interesting aspect is related with the memory location of the
variable with the type const. It is said that the compiler can put
this variable in a read-only memory zone. I have a couple of
questions:

A. is there a compiler option to force constants to be placed in a
read-only memory zone? (I've searched for that but did not find
anything) How this read-only memory (write protected) is set up?

B. there are two cases where the read-only memory zone should be
implemented:
B1. the constant knows its initial value at compile time
B2. the constant knows its initial value at run time (e.g. the const
parameter of a function)
For B2 case, how a read-only memory zone can be implemented?

And a last comment, a variable with const and volatile types cannot be
put in a read-only memory zone because of the volatile type (the
memory location can be written by the other party and therefore cannot
be read-only)

Regards,
Teo
 
F

Floare Augustin Theodor

And a last comment, a variable with const and volatile types cannot be
put in a read-only memory zone because of the volatile type (the
memory location can be written by the other party and therefore cannot
be read-only)

If this is really true then the variable with const and volatile types
can be modified (using a cast) and because there is no underlying read-
only memory, the “undefined behavior” behind the fact that a const is
modified becomes a “misconduct behavior” with a predictable result
(therefore is not at all, in this case, an “undefined behavior”).
 
R

red floyd

Floare said:
And a last comment, a variable with const and volatile types cannot be
put in a read-only memory zone because of the volatile type (the
memory location can be written by the other party and therefore cannot
be read-only)

Sure it can. Consider a memory-mapped, read only register.

const volatile unsigned char *const SOME_REG =
(const volatile unsigned char *)0xFFFFE080;
 
J

James Kanze

By having a variable of type const, initialized with a value,
the compiler is likely to replace every instance of the
variable with its initial value. To impede this optimization
of compiler, the variable will be defined with type const and
type volatile. In this case every instance of the variable
will access the memory location of the variable.
One interesting aspect is related with the memory location of
the variable with the type const. It is said that the compiler
can put this variable in a read-only memory zone. I have a
couple of questions:
A. is there a compiler option to force constants to be placed
in a read-only memory zone? (I've searched for that but did
not find anything) How this read-only memory (write protected)
is set up?

It depends on the compiler. Most compilers will put const
variables with static lifetime and static initialization in
read-only memory by default. For other const variables, it's
generally not possible.
B. there are two cases where the read-only memory zone should be
implemented:
B1. the constant knows its initial value at compile time
B2. the constant knows its initial value at run time (e.g. the
const parameter of a function)
For B2 case, how a read-only memory zone can be implemented?

For the B2 case, there are two solutions. The first would
probably involve putting each affected variable in a separate
page, and use system specific requests to write protect the page
after initialization. In general, this would invalidate the
system specific API in the case of auto variables, but an
implementation could conceivably put all const variables with
static lifetime but dynamic initialization in special pages,
making them write protected once initialization has terminated.
The second is simply to track the information as to what is
const, and check on each write---something similar to the way
Purify tracks invalid reads and writes (but Purify doesn't
handle const, since it doesn't look at the source code).
And a last comment, a variable with const and volatile types
cannot be put in a read-only memory zone because of the
volatile type (the memory location can be written by the other
party and therefore cannot be read-only)

A volatile const variable can be put in read only memory in the
process in which it is declared volatile const. That wouldn't
stop another process from writing it. In practice, of course,
volatile is only useful in cases where special hardware is
involved. And the link process, or some other technique, is
used to ensure that the volatile object corresponds to the
address of that special hardware. (Note that with most
compilers, on most modern architectures, volatile doesn't
actually do anything useful anyway, even when special hardware
is involved.) And there is no reason to believe that you can
write to a const volatile object.
 
J

James Kanze

If this is really true then the variable with const and
volatile types can be modified (using a cast) and because
there is no underlying read-only memory, the “undefined
behavior” behind the fact that a const is modified becomes a
“misconduct behavior” with a predictable result (therefore is
not at all, in this case, an “undefined behavior”).

Nonsense. Just because a memory address is read-only to your
program doesn't mean that it can't be modified elsewhere. The
classical example is some sort of real-time clock. It's value
can obviously change between two reads, but you still can't
(necessarily) write it.

And as I've already pointed out, this won't work today with most
compilers on modern processors. Something like:
int volatile* p = someHardwareAddress ;
// ...
int i ;
i = *p ;
i = *p ;

does not guarantee two reads to the hardware device with Sun CC
or g++ on a Sparc, g++ on a PC under Linux or VC++ on a PC under
Windows.

In practice, you can pretty much forget about volatile on a
modern, general purpose machine.
 
F

Fred Zwarts

James Kanze said:
Nonsense. Just because a memory address is read-only to your
program doesn't mean that it can't be modified elsewhere. The
classical example is some sort of real-time clock. It's value
can obviously change between two reads, but you still can't
(necessarily) write it.

And as I've already pointed out, this won't work today with most
compilers on modern processors. Something like:
int volatile* p = someHardwareAddress ;
// ...
int i ;
i = *p ;
i = *p ;

does not guarantee two reads to the hardware device with Sun CC
or g++ on a Sparc, g++ on a PC under Linux or VC++ on a PC under
Windows.

In practice, you can pretty much forget about volatile on a
modern, general purpose machine.

I am not sure that I completely understand what you mean.
Do these compilers violate the C++ standard, or do you mean that the
C++ standard does not guarantee these reads?
I think that in device drivers it may be very important that in the above case
really two reads to the hardware are executed. Not only to read a value,
but also because reading a register may have a side-effect, like resetting a device,
or emptying a fifo buffer.
I thought that the C++ guarantees the reads to the hardware is such cases.
If not, a wonder whether C++ can still be used to write device drivers.
 
B

Bart van Ingen Schenau

Floare said:
This is the exact quote from Herbert Schildt ("C The Complete
Reference"):

"You can also use const to verify that your program does not modify a
variable.

Agreed so far.
Remember, a variable of type const can be modified by
something outside your program. For example, a hardware device may set
its value.

Here, Mr. Schildt leaves out a very important piece of information:
Unless a variable has been declared with 'volatile' qualification,
external events (such as hardware devices) are assumed NOT to interfere
with the variables in your program.

For that reason, if you have a variable 'const int ct = 10;' then the
compiler can choose to place that variable in physically read-only
memory (or tell the MMU/CPU that the memory is read-only).
However, by declaring a variable as const, you can prove
that any changes to that variable occur because of external events."

This is false, because the compiler can generate code under the
assumption that such external events can't exits.

Bart v Ingen Schenau
 
F

Floare Augustin Theodor

"C The Complete Reference", and most other books written by Schildt,
are steaming piles of excrement.  See the link below:

http://www.seebs.net/c/c_tcr.html


That is an exaggeration. I've looked at the indicated page and I can
tell that for:

------------------------------
"Page 19

In general, negative numbers are represented using the two's
complement approach...

This is not a C feature. It is a common implementation, but it is
specifically not required. (Binary is, but one's complement is not
unheard of.)"
------------------------------

"In general, negative numbers are represented using the two's
complement approach... " That is true, but the author does not say
that it is or it is not a C feature. Following this logic, we can say,
there are a lot of words in his book that are not C keywords! :)


and
------------------------------
"Page 53

printf("%f", sizeof f);
printf("%d", sizeof(int));

Clearly wrong; sizeof is not a double or float. It is also not an
int; it is an unsigned integral type, thus, one of unsigned char,
unsigned short, unsigned int, or unsigned long.

The only safe way to do this is:

printf("%lu", (unsigned long) sizeof(int));

While this is larger, a clear explanation of why it is required
will go a long way towards helping people understand C."
------------------------------

Here, the argument does not fit because sizeof is an unary compile-
time operator. The proof:
int s = sizeof(int);
is translated into
mov DWORD PTR _s$[ebp], 4

Therefore, sizeof(int) is replaced with an integer number and that
number can be printed as an integer or as a float.


Regards,
Teo
 
A

Alf P. Steinbach

* Floare Augustin Theodor:
That is an exaggeration. I've looked at the indicated page and I can
tell that for:

------------------------------
"Page 19

In general, negative numbers are represented using the two's
complement approach...

This is not a C feature. It is a common implementation, but it is
specifically not required. (Binary is, but one's complement is not
unheard of.)"
------------------------------

"In general, negative numbers are represented using the two's
complement approach... " That is true, but the author does not say
that it is or it is not a C feature. Following this logic, we can say,
there are a lot of words in his book that are not C keywords! :)

It's difficult to say anything about a quote taken out of context, but on its
own Schildt is correct here, it's true that most C and C++ implementations,
almost all of them, use two's complement form for signed integer types, although
Schildt's use of weasel words ("in general"), overspecificity ("negative") and
needless generalization ("numbers") means that it's possible to interpret it
adversarially as incorrect.

and
------------------------------
"Page 53

printf("%f", sizeof f);
printf("%d", sizeof(int));

Clearly wrong; sizeof is not a double or float. It is also not an
int; it is an unsigned integral type, thus, one of unsigned char,
unsigned short, unsigned int, or unsigned long.

The only safe way to do this is:

printf("%lu", (unsigned long) sizeof(int));

While this is larger, a clear explanation of why it is required
will go a long way towards helping people understand C."
------------------------------

Here, the argument does not fit because sizeof is an unary compile-
time operator. The proof:
int s = sizeof(int);
is translated into
mov DWORD PTR _s$[ebp], 4

Therefore, sizeof(int) is replaced with an integer number and that
number can be printed as an integer or as a float.

Schildt's first printf is incorrect, just Undefined Behavior.

So, of the two alleged critcism errors you've quoted from the Schildt bashing
page, 1 is not an error and 1 is an error.

I write "bashing" page because it's so unnecessary to drop down to the same
level of inaccuracy as that one is criticizing (whoever made that page).


<q>
Page 33

The following heading occurs:
"static Global Variables"

No such thing. A static variable outside of a function has file scope, which is
distinct from global scope.
</q>

This is just verbiage, an adversarial interpretation: the word "global" has a
language-independent common meaning (the opposite of "local") where Schildt's
heading is meaningful. Anyway it's silly to attack a book on a difference over
what a word "should" mean, or by imposing a clearly unintended context. If the
author implicitly or explicitly defines the word (I don't know if Schildt does)
then all's fine, regardless of whether someone disagrees about ideal usage.


<q>
Page 53
The following code:
"
/* Write 6 integers to a disk file. */
void put_rec(int rec[6], FILE *fp)
{
int len;

len = fwrite(rec, sizeof rec, 1, fp);
if (len != 1) printf("write error");
}
"

Is described as causing all of rec to be written, no matter what size of array
is being used.

Incorrect.
</q>

This is true, Schildt's code is completely nuts.


<q>
Page 59
"This shorthand works for all the binary operators... "

No, it doesn't. It doesn't work for ".", "->", "&&", or "||". For that matter,
it doesn't work for the function call operator or the array operator, both of
which are, roughly, binary operators.
</q>

The "No, it doesn't" is a correct criticism. The commentary about function call
operator and array operator is nonsense.


<q>
Page 63

If scanf fails, the variable guess is referenced before it has been initialized;
accessing an uninitialized object introduces undefined behavior.
</q>

Since no quote from the Schildt book is provided for this criticism, it's
impossible for me to say whether the criticism here is correct, but it seems
likely that it is correct (i.e. that Schildt has a bug in his code).



After this follows about 15 more critcisms which (assuming the Schildt quotes
are correct) *are* correct, where it's demonstrated that Schildt lacks
fundamental knowledge and insight about the matters he writes about.

So, out of about 20-21 criticisms (I'm too lazy to count), about 2 are incorrect
adversarial interpretation criticisms, 1 is half correct half nonsense, and the
rest of the critcisms seem to be correct.

Which, considering how basic the stuff is that Schildt discusses and get
completely wrong, means that the bashing page's title, "C: The Complete
Nonsense", is probably not at all misleading.


Cheers & hth.,

- Alf

CC: The bashing page author (since there was a mail-address at the bottom).
 
F

Floare Augustin Theodor

Schildt's first printf is incorrect, just Undefined Behavior.

I didn't know that
printf("%f", 2)
is not going to print 2.00000.
Actually, it prints 0.00000.

2 does not have the correct type (=> undefined behavior), but on my
machine sizeof(int) = sizeof(float) = 4 bytes.
So, printf will reinterpret the 32 bits of the integer as being the 32
bits of a float?

Regards,
Teo
 
C

crisgoogle

I didn't know that
printf("%f", 2)
is not going to print 2.00000.
Actually, it prints 0.00000.

2 does not have the correct type (=> undefined behavior), but on my
machine sizeof(int) = sizeof(float) = 4 bytes.
So, printf will reinterpret the 32 bits of the integer as being the 32
bits of a float?

That probably explains what you're seeing, yes.

But keep in mind that _even if_ sizeof (int) == sizeof(float), this
does not mean that the the printf will reinterpret the bits.

The line quite simply has undefined behaviour, and may, as in this
case,
do something that can be relatively easily explained. But it may do
something else completely different, and much harder to explain,
with a different compiler or different settings, etc, etc.

(Now that I think of it of course, the behaviour you're seeing easily
could have nothing to do with the bits of the int being reinterpreted
as a float. It could be, for example, that a floating point register
with the contents 0.0 is being printed out, and the int argument is
actually in a totally different location.)
 
F

Floare Augustin Theodor

I didn't know that
printf("%f", 2)
is not going to print 2.00000.
Actually, it prints 0.00000.

2 does not have the correct type (=> undefined behavior), but on my
machine sizeof(int) = sizeof(float) = 4 bytes.
So, printf will reinterpret the 32 bits of the integer as being the 32
bits of a float?

Regards,
Teo

I am wrong again (that is why is hard to write a book :) you need to
keep testing the code over and over again and read the manual too).
I am wrong because %f does not come from float.
printf("%f", 2); will try to print a double (not a float)
Now, I think the mechanism is this: when printf is called, value 2, is
put on stack as an int (4 bytes).
And printf will try to read a double (8 bytes) and will read beyond
what is allowed.

Regards,
Teo
 
R

Rolf Magnus

James said:
Yes, but since a variable is an object, the properties of that
object can be applied to it.

Yes.
The C++ standard does use the term "const variables" (in §5.19), although
in other contexts, it prefers "const object" (doubtlessly because not all
objects are variables).

Can an object that is not a variable be const?
 
A

Alf P. Steinbach

* Rolf Magnus:
Can an object that is not a variable be const?

That's the question... In my view yes, and I believe that's the general
consensus. It's a little subtle though, and depends not only on interpretation
of the standard for various constructs, but also interpretation of what exactly
does "variable" mean.

int const& x = 3;

In strict terms it seems that x is not a variable but a reference, referring to
an anonymous object that is const. But one may argue that what's here is an
object with a name, hence it's a variable. And what else could one call x than a
variable, considering that its type in C++98 for all practical purposes is just
'int', the '&' completely undetectable? This is the "quacks like, waddles like,
looks like..." argument, a.k.a. the effective behavior argument (does it make
sense to use different terms when the behavior is identical?). Plus one may
argue the opposite way that x refers to an object that isn't originally const.

Terminology-debate aside, for the in-practice it's clearly not a good idea to
cast away constness and try to modify that object...


Cheers,

- Alf
 
B

Bart van Ingen Schenau

Floare said:
I am wrong again (that is why is hard to write a book :) you need to
keep testing the code over and over again and read the manual too).

You have that the wrong way around. To be able to meaningfully test the
code, you must first have read and understood the manual. C++ is a
language with too many subtleties that you can not learn C++ programming
from experimentation alone. You very much need a *good* book (which
Schildt is not).
I am wrong because %f does not come from float.
printf("%f", 2); will try to print a double (not a float)
Now, I think the mechanism is this: when printf is called, value 2, is
put on stack as an int (4 bytes).
And printf will try to read a double (8 bytes) and will read beyond
what is allowed.

That might be what YOUR compiler is doing.
The mechanism with MY compiler is that on the call-site the value 2 is
places in an integer register, and then printf tries to read the
argument from an (uninitialised) floating-point register.
As a result, the program crashes, because that float register happened
to contain a signalling NaN.
Regards,
Teo

Bart v Ingen Schenau
 
B

Bo Persson

Floare said:
I am wrong again (that is why is hard to write a book :) you need
to keep testing the code over and over again and read the manual
too).

Like others have said, you cannot rely on tests alone - because as
soon as you involve some undefined behavior, the test results are not
reliable.

You have to read the manual, or your textbook, FIRST.


Bo Persson
 
T

tristan

The following is the assembly code for the below C++ code:
0x40096e push rbp
0x40096f mov rbp,rsp
0x400972 sub rsp,0x10

////////////////////////////////////////////////////////////////////////////////////////
0x400976 mov DWORD PTR [rbp-0x4],0x14
0x40097d lea rax,[rbp-0x4]
0x400981 mov QWORD PTR [rbp-0x10],rax
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
0x400985 mov rax,QWORD PTR [rbp-0x10]
0x400989 mov DWORD PTR [rax],0xe9
////////////////////////////////////////////////////////////////////////////////////////
0x40098f mov rsi,QWORD PTR [rbp-0x10]
0x400993 mov edi,0x601060
0x400998 call 0x4007e8 <_ZNSolsEPKv@plt>
0x40099d mov rdi,rax
0x4009a0 mov esi,0x400afc
0x4009a5 call 0x4007d8
<_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x4009aa mov rdi,rax
0x4009ad lea rsi,[rbp-0x4]
0x4009b1 call 0x4007e8 <_ZNSolsEPKv@plt>
0x4009b6 mov rdi,rax
0x4009b9 mov esi,0x400808
0x4009be call 0x4007f8 <_ZNSolsEPFRSoS_E@plt>
0x4009c3 mov rax,QWORD PTR [rbp-0x10]
0x4009c7 mov esi,DWORD PTR [rax]
0x4009c9 mov edi,0x601060
0x4009ce call 0x400788 <_ZNSolsEi@plt>
0x4009d3 mov rdi,rax
0x4009d6 mov esi,0x400afc
0x4009db call 0x4007d8
<_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
///////////////////////////////////////ct/////////////////////////////////////////////////
0x4009e0 mov rdi,rax
0x4009e3 mov esi,0x14 // Here is the optimization!!!
0x4009e8 call 0x400788 <_ZNSolsEi@plt>
////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////*p/////////////////////////////////////////////////
0x4009ed mov rdi,rax
0x4009f0 mov esi,0x400808
0x4009f5 call 0x4007f8 <_ZNSolsEPFRSoS_E@plt>
////////////////////////////////////////////////////////////////////////////////////////
0x4009fa mov eax,0x0
0x4009ff leave
0x400a00 ret

Jack Klein 写é“:
 
F

Floare Augustin Theodor

"The result is implementation-defined if an attempt is made to change
a const."
from "The C programming language" by Brian Kernighan, Dennis Ritchie

Regards,
Teo
 

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

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,197
Latest member
Sean29G025

Latest Threads

Top