Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #142991 > unrolled thread

Scopes of identifiers

Started byThiago Adams <thiago.adams@gmail.com>
First post2019-04-10 16:15 -0700
Last post2019-04-11 23:26 -0400
Articles 20 on this page of 41 — 14 participants

Back to article view | Back to comp.lang.c


Contents

  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 →


#142991 — Scopes of identifiers

FromThiago Adams <thiago.adams@gmail.com>
Date2019-04-10 16:15 -0700
SubjectScopes 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]


#142992

FromBart <bc@freeuk.com>
Date2019-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]


#142994

FromThiago Adams <thiago.adams@gmail.com>
Date2019-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]


#142995

FromThiago Adams <thiago.adams@gmail.com>
Date2019-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]


#142993

FromThiago Adams <thiago.adams@gmail.com>
Date2019-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]


#142996

FromRobert Wessel <robertwessel2@yahoo.com>
Date2019-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]


#142997

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2019-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]


#142999

FromKeith Thompson <kst-u@mib.org>
Date2019-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]


#143000

Fromluser droog <luser.droog@gmail.com>
Date2019-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]


#143020

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2019-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]


#143022

Fromscott@slp53.sl.home (Scott Lurndal)
Date2019-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]


#143024

FromThiago Adams <thiago.adams@gmail.com>
Date2019-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]


#143046

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-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]


#143059

FromThiago Adams <thiago.adams@gmail.com>
Date2019-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]


#143060

FromThiago Adams <thiago.adams@gmail.com>
Date2019-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]


#143035

FromKeith Thompson <kst-u@mib.org>
Date2019-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]


#143092

FromNick Bowler <nbowler@draconx.ca>
Date2019-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]


#143002

FromBart <bc@freeuk.com>
Date2019-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]


#143011

FromBart <bc@freeuk.com>
Date2019-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]


#143017

FromKeith Thompson <kst-u@mib.org>
Date2019-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