Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
The code we're discussing was snipped at some point, so here it
is again:
int main(void) {
int obj = 42;
typedef void func(void);
if (0) {
func *fptr = (func*)&obj;
fptr();
}
}
It illustrates the issue that the standard does not define the behavior
of a conversion from an object pointer type to a function pointer type
(other than the special case of a null pointer constant), but does not
make such conversion, expressed as a cast, a constraint violation.
I asked: "On what basis do you think a conforming implementation may
reject it?
The code is not strictly conforming.
Do you see a syntax rule or constraint that it violates?
No.
Do you see some other basis for rejecting it?"
Yes. The conversion expression can be untranslatable on some
platforms. That means any such expression cannot be part of
a strictly conforming program.
I disagree. A conforming implementation could implement a
conversion of an object pointer to a function pointer that always
yields a null pointer, or that yields a pointer whose representation
is derived from the representation of the operand. The latter is
typically done for pointer-to-integer or integer-to-pointer
conversions with mismatched sizes (6.3.2.3 explicitly says that
integers may be converted to pointers and vice versa).
If, hypothetically, the standard said that an otherwise valid
program containing a conversion of an object pointer to a function
pointer type must be successfully translated, then compiler
implementers could easily find a way to implement such conversions,
even if the result is not useful. It is incorrect to claim that
such a conversion expression may be "untranslatable".
I have no interest in treating you as a student. I'd be much
happier if you would do more thinking for yourself.
I would be happier if you would not assume that I'm not already
doing that.
Be less arrogant.
An exception to that rule is elaborate
function pointers, which can use very large structured values to
represent a pointer to function.
On Fri, 19 Jan 2024 12:49:57 -0800, Tim Rentsch wrote:
An exception to that rule is elaborate
function pointers, which can use very large structured values to
represent a pointer to function.
Real-world example: PowerPC/POWER, where a function reference is two >addresses, one for the code and the other for, I think it’s called the GOT >(“Global Object Table”). Every piece of code assumes its GOT register has >been set up with the right value.
.. GOT (Global Offset Table) ...
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.T...@gmail.com> writes:
The code we're discussing was snipped at some point, so here it
is again:
int main(void) {
int obj = 42;
typedef void func(void);
if (0) {
func *fptr = (func*)&obj;
fptr();
}
}
It illustrates the issue that the standard does not define the
behavior of a conversion from an object pointer type to a function
pointer type (other than the special case of a null pointer
constant), but does not make such conversion, expressed as a cast,
a constraint violation.
I asked: "On what basis do you think a conforming implementation
may reject it?
The code is not strictly conforming.
Do you see a syntax rule or constraint that it violates?
No.
Do you see some other basis for rejecting it?"
Yes. The conversion expression can be untranslatable on some
platforms. That means any such expression cannot be part of
a strictly conforming program.
The committee has officially ruled in DR 109 that code with undefined behavior renders the program not strictly conforming, only if execution
of that code is an inevitable consequence of running the program. Not
only is execution of this code not inevitable, it is in fact impossible
for it to be executed.
I'm curious - on what platform is it impossible, or at least
difficult, to translate an if(0) block as a no-op? I'd think that
simply failing to generate any corresponding machine code would be
sufficient on most, if not all, platforms.
The code that appeared in DR 109 was not a no-op, but the behavior
of any program that called the function would be undefined, which
means that the standard imposes no requirements on its behavior.
On what platform is it difficult to generate code that has no
requirements on how it behaves? I'd think it would be trivial
translate it as, for instance, the equivalent of
fprintf(stderr, "ISO C does not define the behavior of converting \n"
"a pointer to an object into a pointer to a function.\n"); exit(EXIT_FAILURE);
On 2023-11-19 at 02:28 EST, Tim Rentsch wrote:
James Kuyper <james...@alumni.caltech.edu> writes:
Most fundamentally, what I an hoping to accomplish is to convince
you to answer Keith's question.
Consider a C compiler for a machine where function pointers are
much bigger than any object pointer type. Functions might even
live in a completely different address space than data (a
so-called Harvard architecture). On such a machine there is no
sensible way to change an object pointer into a function pointer,
or vice versa. Naturally the compiler would prefer to choose not
to translate any source file that contains such a conversion.
But the standard does not allow such behavior -
if they wish to
claim conformance to the C standard, they'll have to do something
other than what they'd prefer. Since the code with undefined
behavior is protected by an if(0), an implementation is not
required to generate the impossible conversion code, and is
required to accept the program.
The C standard doesn't say function pointers may be converted to
object pointers, or the other way around. The obvious thing to
do is simply give an error message and forego the translation
effort. It doesn't make sense that the standard would insist
that an implementation translate a construct that is nonsensical,
not just in a particular case but in every possible case.
I appreciate that you feel that way - but the committee resolved
DR 109 in conflict with your feeling.
The code referred to by DR
109 divided an integer by an integer constant of 0, which wasn't
even protected by an if(0). It was the only line in the only
function defined in that translation unit, which was absolutely
guaranteed, if function were called, to execute that line. The
only reason the committee gave for it being strictly conforming
was that there was no guarantee that the rest of the program ever
actually called the function. But the committee decided that that
fact was sufficient to make the code, in itself, strictly
conforming, and the implementation was therefore required to
accept it. If the program as a whole did call that function, that
fact would be sufficient to justify rejecting the whole program,
but it was not sufficient to justify rejecting that particular
translation unit.
Basically, code with undefined behavior prevents a program from
being strictly conforming only if execution of such code is an
inevitable consequence of starting the program. If executing that
code can be avoided, then only a failure to avoid it renders the
the behavior undefined. If that failure is not realized at
compile time, then the implementation must still accept it.
If the committee ruled that way on that code, how could you
possibly expect it to support rejection of this code?
Converting between function pointers and object pointers isn't
like dividing by zero.
True - there's implementations which can meaningfully do such a
conversion - there's no meaningful way to divide an integer by 0
(a floating point calculation could reasonably produce infinity,
if infinity can be represented on that hardware). Which makes the committee's decision on DR 109 even stronger.
[.. some remarks unrelated to the primary topic ..]
[...]
However, if you're unable to provide a convincing argument that
your point of view is correct, then it's a point of view that is,
quite frankly, of no interest.
Try compiling Keith's program with gcc -pedantic-errors. I expect
you will find, as I did, that gcc flags the conversion with an
error and doesn't produce an output file. The C standard allows
such behavior only if the source file being compiled is not
strictly conforming. I have more confidence in gcc's understanding
of the C standard than I do in yours.
I have considerable trust in gcc, but more trust in the actual
words of the standard. Where there's a disagreement, I favor the
actual words of the standard.
And, having seen how you interpret the standard, I certainly
trust my interpretation more than yours.
Yes, it does. And I frequently despair of ever figuring out a way
to say what I mean that will be understood as intended by you.
[...]
The problem is not me understanding you, but you not understanding
me. Your mental model for how to use and understand natural
language is peculiar. Also rigid and inflexible. Probably the
most troublesome property is that you are focused on argument more
than on understanding. You read the words but don't understand the
meaning. Instead you insist on playing idiosyncratic word games,
apparently believing that how you interpret the words is universal
and absolute. It isn't. Assigning meaning to natural language is
inherently a subjective process, not an objective one. You're a
lot better at arguing than you are at listening. You might want to
think about that.
Subjectivity is fine for poetry - but we're talking about a
standard. To the extent that the meaning of words is subjective,
they are unsuitable for use in a standard. The whole point of the
standard is to standardize the requirements - that is, to make
them exactly the same for everyone. If you have to use subjective interpretations to determine what the requirements are, the
standard has failed the purpose for which it was intended. An
implementor could use it's subjective opinion to justify
implementing C in a way that would be inconsistent with the
subjective opinion of a user.
Incidentally, both of these message seems to be a response to a
posting (or postings) of mine, but they seem not to be linked
in the usual way that newgroup postings. I'm not sure how or
why that happened, but I thought I should mention it.
[..first message..]
James Kuyper <james...@alumni.caltech.edu> writes:
[Message-ID: <uje6vv$gei$1...@dont-email.me>]
[This message is missing an attribution line that might have
been something like the following line]
The remarks in DR 109 are irrelevant to what I'm saying. The
program given above fails to be strictly conforming for reasons
that have nothing to do with undefined behavior.
I'm curious - on what platform is it impossible, or at least
difficult, to translate an if(0) block as a no-op? I'd think that
simply failing to generate any corresponding machine code would be
sufficient on most, if not all, platforms.
I hope you realize that this question is quite irrelevant to the
matter being addressed here.
The code that appeared in DR 109 was not a no-op, but the behavior
of any program that called the function would be undefined, which
means that the standard imposes no requirements on its behavior.
On what platform is it difficult to generate code that has no
requirements on how it behaves? I'd think it would be trivial
translate it as, for instance, the equivalent of
fprintf(stderr, "ISO C does not define the behavior of converting \n"
"a pointer to an object into a pointer to a function.\n");
exit(EXIT_FAILURE);
You seem to think that the problem has to do with how to compile
program text that has undefined behavior. It doesn't. Please
see also my response to Keith Thompson's message regarding what
I mean by "translatable".
Yes, it does. There's a flaw in your logic in trying to decide
whether the program is strictly conforming.
Let me say again that the question of undefined behavior is
not relevant here. The given program fails to be strictly
conforming for reasons that have nothing to do with undefined
behavior.
The undefined behavior not being evaluated doesn't guarantee the
program is strictly conforming. If a program /is/ otherwise
strictly conforming then undefined behavior that is potentially
unevaluated doesn't interfere with that. Do you see the
difference?
If the committee ruled that way on that code, how could you
possibly expect it to support rejection of this code?
You think the only things that matter in the two programs are
analogous. They aren't.
Again you miss the point. The question of undefined behavior
has no bearing on the conclusion.
I have very little interest in trying to offer an argument
that convinces you. My conclusions are correct, whether
my comments convince you or not.
The problem is not the words of the C standard but what you think
they mean.
I calibrate my understanding of what text in the C standard means
by comparing it with other sources, including especially remarks
written or spoken by C standard committee members in other contexts.
I'm sorry you missed the point of what I was saying.
Just one more item. Here is a quote from the C Rationale document:
Consequences of the treatment of pointer types in the
Standard include:
* [...]
* Even with an explicit cast, it is invalid to convert
a function pointer to an object pointer or a pointer
to void, or vice versa.
Note in particular the word /invalid/. Not undefined, but
invalid. What do you suppose is the basis for that statement?
What bearing does it have on the question being discussed?
What do you think the implications are for the various assertions
made during the discussion?
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 546 |
Nodes: | 16 (2 / 14) |
Uptime: | 47:11:05 |
Calls: | 10,397 |
Calls today: | 5 |
Files: | 14,066 |
Messages: | 6,417,277 |
Posted today: | 1 |