0

I am confused why I get the error message "src/parser.c:13:1: error: unknown type name 'declared_idents'; did you mean 'declared_t'?" when I declare the struct declared_idents prior to defining the members of the struct.

However, when I move the declared_idents.declared_list and declared_idents.declared_list_length definitions inside the function "is_declared" my code compiles fine. Why is this happening? My code is below:

Parser.c

#include "../include/parser.h"
#include "../include/lexer.h"

operators_t operators[] = {
    {"=", 201}, {"+", 202}, {"-", 203}, {"*", 204}, {"/", 205},
    {"==", 206}, {"!=", 207}, {"<", 208}, {"<=", 209}, {">", 210}, {">=", 211}, 
};
int operators_length = sizeof(operators)/sizeof(operators[0]);

declared_t declared_idents;
char declare_container[TOKEN_BUFSIZE][BUFSIZE];

declared_idents.declared_list = &declare_container;
declared_idents.declared_list_length = 5;

int is_declared(char *identifier) {

    int i = 0;

    for (i; i < declared_idents.declared_list_length; i++) {
        if (strcmp(identifier, declared_idents.declared_list[i]) == 0) {
            return 1;
        }
    }

    declared_idents.declared_list[i] = *identifier;
    (declared_idents.declared_list_length)++;

    return 0;
}

Moving the definitions at the top of the file into the function "int is_declare(..) compiles with no errors:

int is_declared(char *identifier) {
declared_idents.declared_list = &declare_container;
declared_idents.declared_list_length = 5;
}

Parser.h

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define BUFSIZE 1024
#define TOKEN_BUFSIZE 64

typedef struct {
    char **declared_list;
    int declared_list_length;
} declared_t;

int is_declared(char *identifier);

When I read the logs from the compiler, I see that it reads the header file "src/../include/parser.h:15:3: note: 'declared_t' declared here } declared_t;" after flagging the error.

  • 6
    `declared_idents.declared_list = &declare_container; declared_idents.declared_list_length = 5;` You can't place code like that outside a function... You can use an initializer but not an assignment operator – Support Ukraine Feb 20 '23 at 20:23
  • 1
    Further... `&declare_container` doesn't have type `char**` – Support Ukraine Feb 20 '23 at 20:25
  • 3
    That said.... Stop using those global variables. In 999 out of 1000 cases use of globals are bad design. So if you are new to C make it a rule never to use a global variable. Using global variables and `scanf` is for experts only and experts (nearly) never do. – Support Ukraine Feb 20 '23 at 20:28
  • As a side note, names ending with `_t` are [reserved by libc](https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html), [reserved by POSIX](https://stackoverflow.com/a/12727104/11082165), and for some prefixes, reserved by the C standard (7.31.12). It's generally unwise to create your own typedefs that conflict with that space. – Brian61354270 Feb 20 '23 at 20:35
  • @Brian To be clear: "names ending with `_t`" are not reserved by C nor the C lib. Some implementations impose that restriction, but the C standard does not. – chux - Reinstate Monica Feb 20 '23 at 21:24
  • @chux-ReinstateMonica Fair enough, they are only "potentially reserved" in the C standard. But the difference between what the standard calls "reserved" and "potentially reserved" is a technical one, and they may as well be treated the same. Point in case, using identifiers end `_t` means that your program _may_ have undefined behavior in future revisions of C. In any informal context, I would call _names set aside to enable potentially code-breaking changes without warning_ as being reserved. – Brian61354270 Feb 20 '23 at 22:31
  • @Brian I find "Typedef names beginning with `int` or `uint` and ending with `_t` may be added to the types defined in the header." but nothing about "potentially reserved" in the C standard concerning general "names ending with _t" to support your comment. Please cite where in the C standard you find support for that or are you suggesting because they are reserved by some other spec, that makes them "potentially reserved" in C too? – chux - Reinstate Monica Feb 20 '23 at 22:47
  • @chux-ReinstateMonica I was pulling from the C++23 draft I had on hand ([N2731](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2731.pdf)), which states "Typedef names beginning with int or uint and ending with _t are potentially reserved identifiers", and under 6.4.2, that "...A potentially reserved identifier is an identifier which is not reserved but is anticipated to become reserved by a future version of this document." The language has been revised somewhat in the current latest draft ([N3088](https://open-std.org/JTC1/SC22/WG14/www/docs/n3088.pdf)), but the meaning seems the same. – Brian61354270 Feb 20 '23 at 23:38
  • I concede that the language in drafts needs to be taken with a grain of salt, but the intent of the committee seems fairly clear in both the old wording and the new ones: those names _may_ become reserved (by the standard or by an implementation), and if they do, your program has UB, so touching them is ill-advised. – Brian61354270 Feb 20 '23 at 23:43
  • @Brian 1) linked spec is a C one, not C++, 2) Spec has "beginning with int or uint and ending with _t are potentially reserved identifiers", not "names ending with _t" in general. – chux - Reinstate Monica Feb 21 '23 at 02:52
  • @chux-ReinstateMonica 1) Indeed, this is a C question after all. 2) Indeed, hence "for some prefixes". :) – Brian61354270 Feb 21 '23 at 03:24
  • Ah, I see now why you said C++. It's the C23 draft, not C++23. Must have had my head in C++ land when I wrote that. – Brian61354270 Feb 21 '23 at 03:34

1 Answers1

1

declared_idents.declared_list = &declare_container; and declared_idents.declared_list_length = 5; are statements, not declarations. In the grammar of the C standard, only declarations and preprocessing directives may appear outside of functions.

The error message is due to the compiler attempting to parse those statements as if they were declarations; it is looking for a type specifier and complains when it cannot find a built-in type name or a typedef type name.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312