Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #163260 > unrolled thread
| Started by | Meredith Montgomery <mmontgomery@levado.to> |
|---|---|
| First post | 2021-10-29 21:37 -0300 |
| Last post | 2021-11-01 13:03 +0100 |
| Articles | 9 — 7 participants |
Back to article view | Back to comp.lang.c
on confusing procedure names with the address of procedures Meredith Montgomery <mmontgomery@levado.to> - 2021-10-29 21:37 -0300
Re: on confusing procedure names with the address of procedures Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-10-29 18:29 -0700
Re: on confusing procedure names with the address of procedures Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-10-29 18:33 -0700
Re: on confusing procedure names with the address of procedures Manfred <noname@add.invalid> - 2021-10-30 05:32 +0200
Re: on confusing procedure names with the address of procedures James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-10-30 01:26 -0400
Re: on confusing procedure names with the address of procedures Manfred <noname@add.invalid> - 2021-10-30 19:05 +0200
Re: on confusing procedure names with the address of procedures James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-10-30 15:17 -0400
Re: on confusing procedure names with the address of procedures Bart <bc@freeuk.com> - 2021-10-30 11:36 +0100
Re: on confusing procedure names with the address of procedures Noob <root@127.0.0.1> - 2021-11-01 13:03 +0100
| From | Meredith Montgomery <mmontgomery@levado.to> |
|---|---|
| Date | 2021-10-29 21:37 -0300 |
| Subject | on confusing procedure names with the address of procedures |
| Message-ID | <86bl37e49v.fsf@levado.to> |
I wrote
--8<---------------cut here---------------start------------->8---
int main()
{
char c1;
printf("c1 is at %p\n", &c1);
printf("and the addr of the addr of c1 is at %p\n", &&c1);
}
--8<---------------cut here---------------end--------------->8---
and I didn't this to make any sense. Indeed, I get
--8<---------------cut here---------------start------------->8---
%make nonsense
gcc nonsense.c -o nonsense
nonsense.c: In function 'main':
nonsense.c:12:3: error: label 'c1' used but not defined
12 | printf("c1 is at %p\n", &&c1);
| ^~~~~~
make: *** [<builtin>: nonsense] Error 1
%
--8<---------------cut here---------------end--------------->8---
The error message totally lost me.
But then I wrote
--8<---------------cut here---------------start------------->8---
#include <stdio.h>
int main()
{
printf("main is at %p\n", main);
printf("main is at %p\n", &main);
}
--8<---------------cut here---------------end--------------->8---
and I expected a compilation error of some sort, but I got
--8<---------------cut here---------------start------------->8---
%CFLAGS=-Wall make main-addr
gcc -Wall main-addr.c -o main-addr
%./main-addr.exe
main is at 00007ff617431594
main is at 00007ff617431594
%
--8<---------------cut here---------------end--------------->8---
So main must be stored at 00007ff617431594 and so it becomes unintuitive
that getting the address of main yields the same value.
My interpretation of this last program is that
main = &main
but for the first program
&c1 =/= & &c1
because the right side is nonsensical? It's trying to get the address
of an address, when we should only get the address of a name. Can't get
the address of numbers.
Pretty confusing.
[toc] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2021-10-29 18:29 -0700 |
| Message-ID | <878rybz4dv.fsf@nosuchdomain.example.com> |
| In reply to | #163260 |
ram@zedat.fu-berlin.de (Stefan Ram) writes:
> Meredith Montgomery <mmontgomery@levado.to> writes:
>>printf("and the addr of the addr of c1 is at %p\n", &&c1);
>
> The operand of the unary & operator shall be either a
> function designator, the result of a [] or unary * operator,
> or an /lvalue/ that designates an object that is * not a
> bit-field and is not declared with the register
> storage-class specifier.
>
> The unary & operator yields the /address/ of its operand.
> Such an address is a mere data value, not an object.
> It is not an lvalue. So it does not have an address.
> So, one cannot use "&&c1".
>
> Therefore, the GNU compiler uses "&&" as its notation to
> take the address of a /label/, but this is not standard C.
And gcc does this because "&&" is already a token (the logical "and"
operator). Since C uses the "maximal munch" rule, the sequence
&&c
is tokenized as "&&" followed by "c". If it were legal to apply unary "&"
to a unary "&" operation you'd have to write it as:
& &c
or
&(&c)
That would probably give you (Meredith) an error message closer to what
you were expecting.
The "maximal munch" rule is why
x+++++y
is tokenized as
x ++ ++ + y
(a syntax error) rather than as
x ++ + ++ y
(which could be a valid expression).
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-10-29 18:33 -0700 |
| Message-ID | <86fssje1p7.fsf@linuxsc.com> |
| In reply to | #163260 |
Meredith Montgomery <mmontgomery@levado.to> writes:
> I wrote
>
> [..various confusions..]
I recommend:
One: get in the habit of running gcc in a conforming mode -
gcc -x c -std=c99 -pedantic-errors <whatever>.c
Two: get a copy of the C standard (or a close approximation thereto)
wget http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
(This link is for a corrected draft of C99. It isn't the latest
version of C but for starters it is an excellent reference.)
Three: read section 6.3.2.1 paragraphs 1, 3, and 4.
Four: read section 6.5.3.2
Five: after reading the above and looking again at your code,
if you are still confused ask another question here.
Six: in general, if there is ever a question or confusion you
have about C, first try to find the answer yourself in the
document whose link is given above. If you feel you still
need help then ask in the newsgroup here.
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2021-10-30 05:32 +0200 |
| Message-ID | <sliebn$16l6$1@gioia.aioe.org> |
| In reply to | #163260 |
On 10/30/2021 2:37 AM, Meredith Montgomery wrote:
> I wrote
>
> --8<---------------cut here---------------start------------->8---
> int main()
> {
> char c1;
>
> printf("c1 is at %p\n", &c1);
> printf("and the addr of the addr of c1 is at %p\n", &&c1);
> }
> --8<---------------cut here---------------end--------------->8---
>
> and I didn't this to make any sense. Indeed, I get
>
> --8<---------------cut here---------------start------------->8---
> %make nonsense
> gcc nonsense.c -o nonsense
> nonsense.c: In function 'main':
> nonsense.c:12:3: error: label 'c1' used but not defined
> 12 | printf("c1 is at %p\n", &&c1);
> | ^~~~~~
> make: *** [<builtin>: nonsense] Error 1
> %
> --8<---------------cut here---------------end--------------->8---
>
> The error message totally lost me.
>
> But then I wrote
>
> --8<---------------cut here---------------start------------->8---
> #include <stdio.h>
> int main()
> {
> printf("main is at %p\n", main);
> printf("main is at %p\n", &main);
> }
> --8<---------------cut here---------------end--------------->8---
>
> and I expected a compilation error of some sort, but I got
>
> --8<---------------cut here---------------start------------->8---
> %CFLAGS=-Wall make main-addr
> gcc -Wall main-addr.c -o main-addr
>
> %./main-addr.exe
> main is at 00007ff617431594
> main is at 00007ff617431594
> %
> --8<---------------cut here---------------end--------------->8---
>
> So main must be stored at 00007ff617431594 and so it becomes unintuitive
> that getting the address of main yields the same value.
In expressions where the function name is used (but not as a call to
that function, so not main()), the function is automatically converted
to a pointer to function (similar to arrays that decay to pointers in
many circumstances). So using main and &main as argument to printf
indeed yields the same result: the address of main.
The same applies to the inverse case, if you have a pointer to function:
#include <stdio.h>
void bar()
{
printf("hello\n");
}
int main()
{
void (*foo)() = bar;
// You can execute the call in both of the following ways:
foo(); // the pointer is implicitly dereferenced
(*foo)(); // the pointer is explicitly dereferenced
}
>
> My interpretation of this last program is that
>
> main = &main
>
> but for the first program
>
> &c1 =/= & &c1
>
> because the right side is nonsensical? It's trying to get the address
> of an address, when we should only get the address of a name. Can't get
> the address of numbers.
As a rationale, addresses represent memory locations (for functions it
is a bit more complicated than that, so let's stick to data for this
second part). This means that an address may be taken from objects that
have some memory storage, e.g. c1.
The result of &c1 is indeed a pure value which has no memory storage, so
its address cannot be taken (in fact it may be physically stored in a
register and not in any memory location, but even if it were stored
somewhere in memory, you would miss some identification of that memory
location in order to get its address).
>
> Pretty confusing.
>
Yet pointers and addresses are probably amongst the most powerful
features of C.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2021-10-30 01:26 -0400 |
| Message-ID | <slil2c$pke$1@dont-email.me> |
| In reply to | #163265 |
On 10/29/21 11:32 PM, Manfred wrote: ... > In expressions where the function name is used (but not as a call to > that function, so not main()), the function is automatically converted > to a pointer to function (similar to arrays that decay to pointers in > many circumstances). The rule you're referring to is "A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, 69) or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type"." (6.3.2.1p4). The "69)" refers to footnote 69, which points out that "Because this conversion does not occur, the operand of the sizeof operator remains a function designator and violates the constraints in 6.5.3.4." Note that the only exceptions to that rule are for sizeof and &; there is no exception to that rule for actual function calls. That's good, because the standard imposes a constraint: "The expression that denotes the called function 102) shall have type pointer to function returning void or returning a complete object type other than an array type." (6.5.5.2p1). If it weren't for that automatic conversion, a call to main would require the following syntax: "(&main)()". Note that this is a change that occurred in C90. K&R C had no such conversion, and specified that "A function call is a primary expression followed by parentheses ... The primary expression must be of type "function returning ..."" The conversion and the constraint were both introduced when C was first standardized, so that main() remained a valid function call, albeit for different reasons, both in K&R C and in C90. The purpose of the change was to simplify the use of function pointers. Before the change, they had to be called using (*function_pointer)(). That remains a valid expression, since *function_pointer is an expression of function type, which automatically gets converted back to a pointer, but they can now also be called more directly by using function_pointer(). ... > void (*foo)() = bar; > > // You can execute the call in both of the following ways: > > foo(); // the pointer is implicitly dereferenced That hasn't been true since C90.
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2021-10-30 19:05 +0200 |
| Message-ID | <slju07$1ghj$1@gioia.aioe.org> |
| In reply to | #163266 |
On 10/30/2021 7:26 AM, James Kuyper wrote: > On 10/29/21 11:32 PM, Manfred wrote: > ... >> In expressions where the function name is used (but not as a call to >> that function, so not main()), the function is automatically converted >> to a pointer to function (similar to arrays that decay to pointers in >> many circumstances). > > The rule you're referring to is "A function designator is an expression > that has function type. Except when it is the operand of the sizeof > operator, 69) or the unary & operator, a function designator with type > "function returning type" is converted to an expression that has type > "pointer to function returning type"." (6.3.2.1p4). > The "69)" refers to footnote 69, which points out that "Because this > conversion does not occur, the operand of the sizeof operator remains a > function designator and violates the constraints in 6.5.3.4." > > Note that the only exceptions to that rule are for sizeof and &; there > is no exception to that rule for actual function calls. That's good, > because the standard imposes a constraint: "The expression that denotes > the called function 102) shall have type pointer to function returning > void or returning a complete object type other than an array type." > (6.5.5.2p1). If it weren't for that automatic conversion, a call to main > would require the following syntax: "(&main)()". > > Note that this is a change that occurred in C90. K&R C had no such > conversion, and specified that "A function call is a primary expression > followed by parentheses ... The primary expression must be of type > "function returning ..."" > The conversion and the constraint were both introduced when C was first > standardized, so that main() remained a valid function call, albeit for > different reasons, both in K&R C and in C90. > > The purpose of the change was to simplify the use of function pointers. > Before the change, they had to be called using (*function_pointer)(). > That remains a valid expression, since *function_pointer is an > expression of function type, which automatically gets converted back to > a pointer, but they can now also be called more directly by using > function_pointer(). > Thanks for the detailed reference to the standard. > ... >> void (*foo)() = bar; >> >> // You can execute the call in both of the following ways: >> >> foo(); // the pointer is implicitly dereferenced > > That hasn't been true since C90. > I guess you mean that the pointer is not "dereferenced", but still the expression is a valid call to the function, so the statement "You can execute the call in both ways" still holds.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2021-10-30 15:17 -0400 |
| Message-ID | <slk5nr$km2$1@dont-email.me> |
| In reply to | #163270 |
On 10/30/21 1:05 PM, Manfred wrote: > On 10/30/2021 7:26 AM, James Kuyper wrote: >> On 10/29/21 11:32 PM, Manfred wrote: ... >>> void (*foo)() = bar; >>> >>> // You can execute the call in both of the following ways: >>> >>> foo(); // the pointer is implicitly dereferenced >> >> That hasn't been true since C90. >> > > I guess you mean that the pointer is not "dereferenced", ... Correct. > ... but still the > expression is a valid call to the function, so the statement "You can > execute the call in both ways" still holds. Yes. I didn't think about the possibility that I could have been interpreted as disagreeing with both comments.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-30 11:36 +0100 |
| Message-ID | <slj77j$ufg$1@dont-email.me> |
| In reply to | #163260 |
On 30/10/2021 01:37, Meredith Montgomery wrote:
> 12 | printf("c1 is at %p\n", &&c1);
&& is used for label address with some C implementations. Label c1
doesn't exist. (Variable c1 does, but in C, variables and labels live in
different namespaces; the same names can coexist).
> printf("main is at %p\n", main);
> printf("main is at %p\n", &main);
> }
If you have a function F, then:
F() Calls the function
F Yields its address
&F Yields its address
So F and &F do the same thing. In effect, the first line could also be
written as:
(&F)() Calls the function
[toc] | [prev] | [next] | [standalone]
| From | Noob <root@127.0.0.1> |
|---|---|
| Date | 2021-11-01 13:03 +0100 |
| Message-ID | <slol20$rh5$1@dont-email.me> |
| In reply to | #163260 |
On 30/10/2021 02:37, Meredith Montgomery wrote:
> gcc nonsense.c -o nonsense
> nonsense.c: In function 'main':
> nonsense.c:12:3: error: label 'c1' used but not defined
> 12 | printf("c1 is at %p\n", &&c1);
> | ^~~~~~
As Tim pointed out, your command-line lacks the proper flags to put
GCC in (mostly) conformant mode, and print useful diagnostics.
https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
CFLAGS = -std=c17 -pedantic-errors -Wpedantic -Wall -Werror
Regards.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web