Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #142991 > unrolled thread
| Started by | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| First post | 2019-04-10 16:15 -0700 |
| Last post | 2019-04-11 23:26 -0400 |
| Articles | 20 on this page of 41 — 14 participants |
Back to article view | Back to comp.lang.c
Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-10 16:15 -0700
Re: Scopes of identifiers Bart <bc@freeuk.com> - 2019-04-11 00:33 +0100
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-10 16:45 -0700
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-10 18:31 -0700
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-10 16:34 -0700
Re: Scopes of identifiers Robert Wessel <robertwessel2@yahoo.com> - 2019-04-10 20:50 -0500
Re: Scopes of identifiers James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-04-10 20:02 -0700
Re: Scopes of identifiers Keith Thompson <kst-u@mib.org> - 2019-04-10 20:58 -0700
Re: Scopes of identifiers luser droog <luser.droog@gmail.com> - 2019-04-10 21:48 -0700
Re: Scopes of identifiers Andrey Tarasevich <andreytarasevich@hotmail.com> - 2019-04-11 11:57 -0700
Re: Scopes of identifiers scott@slp53.sl.home (Scott Lurndal) - 2019-04-11 19:12 +0000
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-11 12:35 -0700
Re: Scopes of identifiers Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-04-12 01:11 +0100
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-12 05:29 -0700
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-12 05:39 -0700
Re: Scopes of identifiers Keith Thompson <kst-u@mib.org> - 2019-04-11 14:00 -0700
Re: Scopes of identifiers Nick Bowler <nbowler@draconx.ca> - 2019-04-15 19:48 +0000
Re: Scopes of identifiers Bart <bc@freeuk.com> - 2019-04-11 10:36 +0100
Re: Scopes of identifiers Bart <bc@freeuk.com> - 2019-04-11 14:25 +0100
Re: Scopes of identifiers Keith Thompson <kst-u@mib.org> - 2019-04-11 10:20 -0700
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-11 05:00 -0700
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-11 06:42 -0700
Re: Scopes of identifiers James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-04-11 08:11 -0700
Re: Scopes of identifiers BGB <cr88192@gmail.com> - 2019-04-10 22:35 -0500
Re: Scopes of identifiers Keith Thompson <kst-u@mib.org> - 2019-04-10 22:04 -0700
Re: Scopes of identifiers BGB <cr88192@gmail.com> - 2019-04-11 05:46 -0500
Re: Scopes of identifiers John Bode <jfbode1029@gmail.com> - 2019-04-11 12:04 -0700
Re: Scopes of identifiers James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-04-11 13:18 -0700
Re: Scopes of identifiers Keith Thompson <kst-u@mib.org> - 2019-04-11 14:31 -0700
Re: Scopes of identifiers Andrey Tarasevich <andreytarasevich@hotmail.com> - 2019-04-11 12:28 -0700
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-11 12:50 -0700
Re: Scopes of identifiers James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-04-11 14:20 -0700
Re: Scopes of identifiers Thiago Adams <thiago.adams@gmail.com> - 2019-04-11 14:43 -0700
Re: Scopes of identifiers Andrey Tarasevich <andreytarasevich@hotmail.com> - 2019-04-11 15:04 -0700
Re: Scopes of identifiers Keith Thompson <kst-u@mib.org> - 2019-04-11 17:08 -0700
Re: Scopes of identifiers Andrey Tarasevich <andreytarasevich@hotmail.com> - 2019-04-11 18:45 -0700
Re: Scopes of identifiers James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-04-11 23:16 -0400
Re: Scopes of identifiers Keith Thompson <kst-u@mib.org> - 2019-04-11 20:19 -0700
Re: Scopes of identifiers Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-04-12 14:39 -0700
Re: Scopes of identifiers Ike Naar <ike@sdf.lonestar.org> - 2019-04-13 20:02 +0000
Re: Scopes of identifiers James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-04-11 23:26 -0400
Page 1 of 3 [1] 2 3 Next page →
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-04-10 16:15 -0700 |
| Subject | Scopes of identifiers |
| Message-ID | <098da5fe-31d3-47b7-b695-d4faea10b366@googlegroups.com> |
How scopes are implemented in C compilers?
Sample:
struct X
{
int X;
};
typedef int X;
void F(struct X X)
{
X:
return;
}
I believe they have two stacks of dictionaries (symbol map).
One for
struct/union/enum
and the other for
typedef/function/variables/enum constant
The file scope starts two stacks with one dictionary each.
When the function argument starts a new dictionary is pushed in each
stack. This is also for each { } scope and one for 'for'.
This is the kind of question I think help us to understand the C
language so is on topic here.
But it also can easily go off-topic and can be analysed with more
details at
https://groups.google.com/forum/#!forum/c-compilers
[toc] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-04-11 00:33 +0100 |
| Message-ID | <k3vrE.331681$iiB1.46265@fx08.am4> |
| In reply to | #142991 |
On 11/04/2019 00:15, Thiago Adams wrote:
> How scopes are implemented in C compilers?
>
> Sample:
>
> struct X
> {
> int X;
> };
>
> typedef int X;
>
> void F(struct X X)
> {
> X:
> return;
> }
>
> I believe they have two stacks of dictionaries (symbol map).
>
> One for
> struct/union/enum
> and the other for
> typedef/function/variables/enum constant
>
> The file scope starts two stacks with one dictionary each.
> When the function argument starts a new dictionary is pushed in each
> stack. This is also for each { } scope and one for 'for'.
>
> This is the kind of question I think help us to understand the C
> language so is on topic here.
There are probably many approaches, I can only say what I use, which is:
* One symbol table, which contains multiple instances of the same
identifier, say "A", across the whole module.
* Each instance of A contains a name-space tag (tag/label/other)
* Each instance of A contains a block number (so a function may contain
A-001 and A-002)
* Each instance of A will link to the current function. (So a search to
resolve "A" will only look inside this function and not inside
others.)
* There is a stack of current block numbers. So if blocks are numbers
consecutively, the location where "A" has been seen may be within a
set of nested blocks 001, 003, 004. A search to resolve "A" must match
any "A" in 004 before looking at 003:
* Resolving of A inside a function works by first searching the current
block, eg. 004, so looking at all instances of "A" inside this
function, that match the block number, and namespace tag expected.
* If not found try the next block levels (003 and 001). (The are ways
to skip empty blocks which contain no declarations.)
* Finally try the module scope level (no block number, or 000).
> But it also can easily go off-topic and can be analysed with more
> details at
>
> https://groups.google.com/forum/#!forum/c-compilers
That seems to be closed to everyone, even for viewing, unless they sign up.
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-04-10 16:45 -0700 |
| Message-ID | <0fdde59d-6b51-4767-8e85-0aea8e1f13f4@googlegroups.com> |
| In reply to | #142992 |
On Wednesday, April 10, 2019 at 8:33:43 PM UTC-3, Bart wrote: ... > That seems to be closed to everyone, even for viewing, unless they sign up. Fixed. Thanks.
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-04-10 18:31 -0700 |
| Message-ID | <24ca5c34-2a9d-42ca-bcb9-c44b8274188e@googlegroups.com> |
| In reply to | #142992 |
On Wednesday, April 10, 2019 at 8:33:43 PM UTC-3, Bart wrote: ... > * One symbol table, which contains multiple instances of the same > identifier, say "A", across the whole module. > > * Each instance of A contains a name-space tag (tag/label/other) > > * Each instance of A contains a block number (so a function may contain > A-001 and A-002) ... I have a linked list of symbol tables. The last symbol table added is the current scope. I search the linked list from the last item (current scope) going up to the file scope. Just by the fact of posting here and thinking about it, I found two bugs in my code. One is the scope of variable in for loop and the other is about the diagnostic of having an enum and struct with the same name.
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-04-10 16:34 -0700 |
| Message-ID | <e9d0004b-6a21-43ef-98f6-16ed2152d985@googlegroups.com> |
| In reply to | #142991 |
On Wednesday, April 10, 2019 at 8:16:14 PM UTC-3, Thiago Adams wrote:
> How scopes are implemented in C compilers?
It is also interesting that structs don't introduce scopes.
struct X
{
struct X2
{
int i;
} x2;
int i;
};
We can declare structs inside structs,or enum but not
functions or typedefs.
And I don't have much idea if declaring a function
in a function scope makes sense.
Functions are always in a global scope, but I can declare it
in a function scope?
void F()
{
void F3();
}
void F4()
{
F3();
}
[toc] | [prev] | [next] | [standalone]
| From | Robert Wessel <robertwessel2@yahoo.com> |
|---|---|
| Date | 2019-04-10 20:50 -0500 |
| Message-ID | <4a7taepksjm01hcffam7m25dess59t7t67@4ax.com> |
| In reply to | #142993 |
On Wed, 10 Apr 2019 16:34:18 -0700 (PDT), Thiago Adams
<thiago.adams@gmail.com> wrote:
>On Wednesday, April 10, 2019 at 8:16:14 PM UTC-3, Thiago Adams wrote:
>> How scopes are implemented in C compilers?
>
>It is also interesting that structs don't introduce scopes.
>
>struct X
>{
> struct X2
> {
> int i;
> } x2;
>
> int i;
>};
>
>We can declare structs inside structs,or enum but not
>functions or typedefs.
>
>
>
>
>And I don't have much idea if declaring a function
>in a function scope makes sense.
>
>Functions are always in a global scope, but I can declare it
>in a function scope?
>
>void F()
>{
> void F3();
>}
>
>void F4()
>{
> F3();
>}
That is, of course, a core feature of C++.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2019-04-10 20:02 -0700 |
| Message-ID | <b734ed8a-dcf0-45f7-82ad-fb4fa9e05ba2@googlegroups.com> |
| In reply to | #142993 |
On Wednesday, April 10, 2019 at 7:34:34 PM UTC-4, Thiago Adams wrote:
...
> We can declare structs inside structs,or enum but not
> functions ...
Correct: 6.7.2.1p2
> ... or typedefs.
Correct. A member of a struct or union is allowed to have a specifier-
qualifier-list that may contain any combination of type-specifiers and
type-qualifiers (6.7.2.1p1), but may not have any of the storage-class-
specifiers (6.7.1) or function-specifiers (6.7.4) that are allowed for
declarations in other contexts (6.7p1). Thus, they may not use the
typedef, extern, static, auto, register, or inline keywords.
> And I don't have much idea if declaring a function
> in a function scope makes sense.
Correct: "A label name is the only kind of identifier that has function
scope." (6.2.1p3).
> Functions are always in a global scope, ...
The C standard does not use the term "global scope". Some people use
that term when they should be using the term "file scope". Functions do
NOT always have file scope. All identifiers other than macro names,
macro parameters, and labels follow the same scope rules (6.2.1p4), and
that includes function identifiers.
> ... but I can declare it
> in a function scope?
No, since it's not a label.
> void F()
> {
> void F3();
That is a block-scope declaration. The scope of that declaration ends
with the next line:
> }
>
> void F4()
> {
So there's no declaration in scope for the following function call:
> F3();
> }
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-04-10 20:58 -0700 |
| Message-ID | <lnk1g12nx8.fsf@kst-u.example.com> |
| In reply to | #142993 |
Thiago Adams <thiago.adams@gmail.com> writes:
> On Wednesday, April 10, 2019 at 8:16:14 PM UTC-3, Thiago Adams wrote:
>> How scopes are implemented in C compilers?
>
> It is also interesting that structs don't introduce scopes.
>
> struct X
> {
> struct X2
> {
> int i;
> } x2;
>
> int i;
> };
A member name is associated with its enclosing type, not with a scope.
You can't use the name i without prefixing it with an expression of the
appropriate type followed by a "." or "->" operator.
[...]
> And I don't have much idea if declaring a function
> in a function scope makes sense.
>
> Functions are always in a global scope, but I can declare it
> in a function scope?
>
> void F()
> {
> void F3();
> }
>
> void F4()
> {
> F3();
> }
First, some terminology. There is no "global scope", and "function
scope" applies only to labels. See N1570 6.2.1.
Something declared outside any function has file scope. Something
declared inside a function definition has block scope. (There's also a
"function prototype scope".)
You can declare (but not define) a function at block scope, but there's
rarely a good reason to do so. In old code, you might have declared a
function inside a block in which it's used, but these days it's more
common to declare functions at file scope (if you need a forward
declaration), or just to #include the appropriate header (which will
declare the function at file scope for you).
For example, an old "hello, world" program might look something like
this:
main() {
int printf();
printf("hello, world\n");
}
but in modern C you'd just #include <stdio.h>. (Actually in ancient C
you probably wouldn't have bothered to declare printf, since it returns
an int and the call would be resolved correctly.)
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | luser droog <luser.droog@gmail.com> |
|---|---|
| Date | 2019-04-10 21:48 -0700 |
| Message-ID | <02430ec5-cc07-4ae7-9b39-22b1659e35bb@googlegroups.com> |
| In reply to | #142999 |
On Wednesday, April 10, 2019 at 10:58:36 PM UTC-5, Keith Thompson wrote:
> For example, an old "hello, world" program might look something like
> this:
>
> main() {
> int printf();
> printf("hello, world\n");
> }
>
> but in modern C you'd just #include <stdio.h>. (Actually in ancient C
> you probably wouldn't have bothered to declare printf, since it returns
> an int and the call would be resolved correctly.)
I've seen it more commonly with math functions that return a double, but
as you correctly observe it was often declared inside of the function.
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2019-04-11 11:57 -0700 |
| Message-ID | <q8o2mg$21k$1@dont-email.me> |
| In reply to | #142999 |
On 4/10/2019 8:58 PM, Keith Thompson wrote:
>
> For example, an old "hello, world" program might look something like
> this:
>
> main() {
> int printf();
> printf("hello, world\n");
> }
>
> but in modern C you'd just #include <stdio.h>. (Actually in ancient C
> you probably wouldn't have bothered to declare printf, since it returns
> an int and the call would be resolved correctly.)
This is not entirely accurate. A variadic function (like `printf`) has
to be declared *with prototype*. Calling a variadic function without a
declaration or with a non-prototype declaration results in undefined
behavior. This requirement is present in the language since C89.
The correct version would be
int main()
{
int printf(const char *, ...);
printf("hello, world\n");
}
--
Best regards,
Andrey Tarasevich
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2019-04-11 19:12 +0000 |
| Message-ID | <dkMrE.99323$DD7.57717@fx05.iad> |
| In reply to | #143020 |
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:
>On 4/10/2019 8:58 PM, Keith Thompson wrote:
>>
>> For example, an old "hello, world" program might look something like
>> this:
>>
>> main() {
>> int printf();
>> printf("hello, world\n");
>> }
>>
>> but in modern C you'd just #include <stdio.h>. (Actually in ancient C
>> you probably wouldn't have bothered to declare printf, since it returns
>> an int and the call would be resolved correctly.)
>
>This is not entirely accurate. A variadic function (like `printf`) has
>to be declared *with prototype*. Calling a variadic function without a
>declaration or with a non-prototype declaration results in undefined
>behavior. This requirement is present in the language since C89.
Ancient C predates C89 by well over a decade, and Keith is correct, it was
not necessary to declare a prototype for it.
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-04-11 12:35 -0700 |
| Message-ID | <c02250b3-87cc-4b99-9bd6-1bb64658971d@googlegroups.com> |
| In reply to | #143022 |
On Thursday, April 11, 2019 at 4:12:19 PM UTC-3, Scott Lurndal wrote:
> Andrey Tarasevich writes:
> >On 4/10/2019 8:58 PM, Keith Thompson wrote:
> >>
> >> For example, an old "hello, world" program might look something like
> >> this:
> >>
> >> main() {
> >> int printf();
> >> printf("hello, world\n");
> >> }
> >>
> >> but in modern C you'd just #include <stdio.h>. (Actually in ancient C
> >> you probably wouldn't have bothered to declare printf, since it returns
> >> an int and the call would be resolved correctly.)
> >
> >This is not entirely accurate. A variadic function (like `printf`) has
> >to be declared *with prototype*. Calling a variadic function without a
> >declaration or with a non-prototype declaration results in undefined
> >behavior. This requirement is present in the language since C89.
>
> Ancient C predates C89 by well over a decade, and Keith is correct, it was
> not necessary to declare a prototype for it.
I wish I could understand how C started because the felling is
that the design is almost by accident.
enuns and structs cannot have the same name. However,
when we use it they are not ambiguous.
enum X e;
struct X x;
First the compiler was implemented in some way
and later the standard was written just to describe
how current compilers were working.
The truth about the design of some items, I guess, is just
because the first implementation did like that.
When I try to find something about the C history I find just:
https://www.bell-labs.com/usr/dmr/www/chist.html
I think old printed magazines also can be interesting but it hard
to find.
Does anyone knows where to find more information about C history?
I would like to have a new C language very compatible with
the old one but not necessarily 100% compatible.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-04-12 01:11 +0100 |
| Message-ID | <87tvf49j60.fsf@bsb.me.uk> |
| In reply to | #143024 |
Thiago Adams <thiago.adams@gmail.com> writes:
<cut>
> I wish I could understand how C started because the [feeling] is
> that the design is almost by accident.
Not really by accident, but early C has a sense of being "just enough"
to get by. For example (directly related to your topic), in early C,
struct members were not associated with structs -- they were simply a
type and offset. You could write
struct { float f; };
struct { int i; } s;
s.i = 42;
printf("%f\n", s.f);
or even
int x = 42;
printf("%f\n", x.f);
to see what float corresponds to the bit pattern for 42. There were no
unions either because you could just do this sort of thing instead.
The information held in the symbol table about f was simply that it was
a float at offset zero from some object. That object could be of any
type.
I know (as an academic) I shouldn't, but I liked that feature! I seemed
to "fit" with how I thought of C at the time.
> When I try to find something about the C history I find just:
>
> https://www.bell-labs.com/usr/dmr/www/chist.html
>
> I think old printed magazines also can be interesting but it hard
> to find.
>
> Does anyone knows where to find more information about C history?
If you go up a level from that link there are some other documents that
will interest you. In particular the old C reference manuals.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-04-12 05:29 -0700 |
| Message-ID | <4ce6da9f-e65c-4c25-b92c-be8d0399343c@googlegroups.com> |
| In reply to | #143046 |
On Thursday, April 11, 2019 at 9:11:42 PM UTC-3, Ben Bacarisse wrote: > Thiago Adams writes: > <cut> > > I wish I could understand how C started because the [feeling] is > > that the design is almost by accident. > > Not really by accident, but early C has a sense of being "just enough" > to get by. For example (directly related to your topic), in early C, > struct members were not associated with structs -- they were simply a > type and offset. You could write Very interesting. To fair, I think it is important to say that some design of the language was limited by the hardware they have at the time. For instance, I believe they didn't check function arguments at the begging and this saved some memory. I think no 1 priority was to generate code. I like this document: Recent Changes to C, November 15, 1978 https://www.bell-labs.com/usr/dmr/www/cchanges.pdf The reason is because enum is a very high level concept in my opinion. There is no enum type inside machines and this feature would unlock new possibilities in code generation Enum is all about making the language better to use. So in 1978 we had this feature included. Comparing with _Bool, that is also a high level feature (using the same logic - we don't have bools inside the machine) it was only included in C99. The other feature added was struct assignment and there is one interesting comment: "Other plausible operators, such as equality comparison, have not been implemented"
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-04-12 05:39 -0700 |
| Message-ID | <6fc4b2d7-f0c6-48c3-92aa-b6c18a09b98d@googlegroups.com> |
| In reply to | #143059 |
On Friday, April 12, 2019 at 9:29:36 AM UTC-3, Thiago Adams wrote: ... > The reason is because enum is a very high level concept > in my opinion. There is no enum type inside machines and > this feature would unlock new possibilities in code generation Fixing (sorry): ..would ** NOT ** unlock new possibilities in code generation.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-04-11 14:00 -0700 |
| Message-ID | <ln7ec02r73.fsf@kst-u.example.com> |
| In reply to | #143020 |
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:
> On 4/10/2019 8:58 PM, Keith Thompson wrote:
>> For example, an old "hello, world" program might look something like
>> this:
>>
>> main() {
>> int printf();
>> printf("hello, world\n");
>> }
>>
>> but in modern C you'd just #include <stdio.h>. (Actually in ancient C
>> you probably wouldn't have bothered to declare printf, since it returns
>> an int and the call would be resolved correctly.)
>
> This is not entirely accurate. A variadic function (like `printf`) has
> to be declared *with prototype*. Calling a variadic function without a
> declaration or with a non-prototype declaration results in undefined
> behavior. This requirement is present in the language since C89.
>
> The correct version would be
>
> int main()
> {
> int printf(const char *, ...);
> printf("hello, world\n");
> }
Of course I'm aware of that (and I should have mentioned it). It was
meant to be an example of a pre-ANSI C program, written when the
language didn't have prototypes or explicitly variadic functions.
In modern C, you could write:
int main(void) {
int printf(const char *restrict format, ...);
printf("hello, world\n");
}
but it's a lot easier just to write:
#include <stdio.h>
int main(void) {
printf("hello, world\n");
}
(and not have to worry about whether "restrict" is supported and/or
needed). But in pre-ANSI C, this:
printf();
or this:
int printf();
would have been the only available way to declare printf.
As someone pointed out, a floating-point function might have made for a
better example:
/* This is pre-ANSI */
main() {
double sqrt();
printf("%f\n", sqrt(2.0));
}
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Nick Bowler <nbowler@draconx.ca> |
|---|---|
| Date | 2019-04-15 19:48 +0000 |
| Message-ID | <q92n6a$elo$1@dont-email.me> |
| In reply to | #143035 |
On Thu, 11 Apr 2019 14:00:00 -0700, Keith Thompson wrote:
> In modern C, you could write:
>
> int main(void) {
> int printf(const char *restrict format, ...);
> printf("hello, world\n");
> }
>
> but it's a lot easier just to write:
>
> #include <stdio.h>
> int main(void) {
> printf("hello, world\n");
> }
>
> (and not have to worry about whether "restrict" is supported
> and/or needed).
There is no need to worry about "restrict" because it is simply
not required. The function types "int(const char *, ...)" and
"int(const char * restrict, ...)" are compatibile types and thus
printf can be declared either way. So it is best to just not use
"restrict" and the declaration will be valid for all C standards.
See C11§6.7.6.3p15:
"In the determination of type compatibility and of a composite
type [with types involving function prototypes], ... each
parameter declared with qualified type is taken as having the
unqualified version of its declared type."
This rule remains essentially unchanged since C89.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-04-11 10:36 +0100 |
| Message-ID | <bUDrE.35723$lc3.35324@fx02.am4> |
| In reply to | #142993 |
On 11/04/2019 00:34, Thiago Adams wrote:
> On Wednesday, April 10, 2019 at 8:16:14 PM UTC-3, Thiago Adams wrote:
>> How scopes are implemented in C compilers?
>
> It is also interesting that structs don't introduce scopes.
>
> struct X
> {
> struct X2
> {
> int i;
> } x2;
>
> int i;
> };
>
> We can declare structs inside structs,or enum but not
> functions or typedefs.
C just doesn't allow it, although the mechanism here is simple.
> And I don't have much idea if declaring a function
> in a function scope makes sense.
>
> Functions are always in a global scope, but I can declare it
> in a function scope?
>
> void F()
> {
> void F3();
> }
>
> void F4()
> {
> F3();
> }
It's what C allows. F3 is visible inside F, but not F4, unless F4 has
its own declaration of F3.
But in that case, both F3s need to refer to the same function, as F3
must exist in a global namespace, just one that is not visible unless a
declaration for it is also visible.
Don't forget that such declarations can also be hidden by being inside
nested block scopes.
(My C compiler doesn't seem to deal which nested functions at all,
whether definitions or declarations. That's OK, it is already a subset
compiler.
gcc and presumably clang allows actual nested function definitions as
extensions. These I guess can also be inside nested block scopes.)
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-04-11 14:25 +0100 |
| Message-ID | <MbHrE.95986$D22.88215@fx35.am4> |
| In reply to | #143002 |
On 11/04/2019 10:36, Bart wrote:
>> void F()
>> {
>> void F3();
>> }
>>
>> void F4()
>> {
>> F3();
>> }
>
> It's what C allows. F3 is visible inside F, but not F4, unless F4 has
> its own declaration of F3.
>
> But in that case, both F3s need to refer to the same function, as F3
> must exist in a global namespace, just one that is not visible unless a
> declaration for it is also visible.
>
> Don't forget that such declarations can also be hidden by being inside
> nested block scopes.
>
> (My C compiler doesn't seem to deal which nested functions at all,
> whether definitions or declarations. That's OK, it is already a subset
> compiler.
>
> gcc and presumably clang allows actual nested function definitions as
> extensions. These I guess can also be inside nested block scopes.)
Funny that within a short time of posting, somebody posts an example
using exactly such a function declaration:
On 11/04/2019 14:07, John Forkosh wrote:
> /* --- test whether or not two ints are equal,
> without comparisons --- */
> #include <stdio.h>
> #include <stdlib.h>
> int main ( int argc, char *argv[] ) {
> int i = (argc>1? atoi(argv[1]) : 1 ),
> j = (argc>2? atoi(argv[2]) : 2 );
> int isequal();
> fprintf( stdout," %d %s %d? \n",
> i, (isequal(i,j)?"==":"=/="), j);
> } /* --- end-of-function main() --- */
>
> int isequal ( int i, int j ) {
> return ( !( abs(i-j) ) );
> } /* --- end-of-function isequal() --- */
The isequal() declaration is inside main().
I've tweaked my compiler to accept this (basically, added a couple of
lines to read the declaration and restrict the error to function
definitions), although the function name still has module-wide scope.
(Which it has to have, but you might want, for some reason, to restrict
its visibility.)
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-04-11 10:20 -0700 |
| Message-ID | <lnbm1c31di.fsf@kst-u.example.com> |
| In reply to | #143011 |
Bart <bc@freeuk.com> writes:
> On 11/04/2019 10:36, Bart wrote:
[...]
> Funny that within a short time of posting, somebody posts an example
> using exactly such a function declaration:
>
> On 11/04/2019 14:07, John Forkosh wrote:
>
> > /* --- test whether or not two ints are equal,
> > without comparisons --- */
> > #include <stdio.h>
> > #include <stdlib.h>
> > int main ( int argc, char *argv[] ) {
> > int i = (argc>1? atoi(argv[1]) : 1 ),
> > j = (argc>2? atoi(argv[2]) : 2 );
> > int isequal();
> > fprintf( stdout," %d %s %d? \n",
> > i, (isequal(i,j)?"==":"=/="), j);
> > } /* --- end-of-function main() --- */
> >
> > int isequal ( int i, int j ) {
> > return ( !( abs(i-j) ) );
> > } /* --- end-of-function isequal() --- */
>
> The isequal() declaration is inside main().
>
> I've tweaked my compiler to accept this (basically, added a couple of
> lines to read the declaration and restrict the error to function
> definitions), although the function name still has module-wide scope.
> (Which it has to have, but you might want, for some reason, to restrict
> its visibility.)
By "module-wide scope", I'm guessing you mean file scope.
The declaration inside main gives the identifier "isequal" block
scope. The declaration that's part of the definition gives it
file scope, but makes it visible only from the declaration to the
end of the file. The name is not visible inside main prior to the
declaration, or outside any function prior to the definition.
(Incidentally, it would be better for the declaration to be a
prototype so the compiler can check that it has the right type.)
Personally, I would either have moved the definition of isequal
above the definition of main, making the extra declaration
unnecessary, or put the "forward" declaration at the top level,
before main(). But declaring it inside a block in main(), where
it's used, is not unreasonable.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | comp.lang.c
csiph-web