gcc compiles fine on the following code
enum AVMediaType {
AVMEDIA_TYPE_UNKNOWN = -1,
AVMEDIA_TYPE_VIDEO,
AVMEDIA_TYPE_AUDIO,
AVMEDIA_TYPE_DATA,
AVMEDIA_TYPE_SUBTITLE,
AVMEDIA_TYPE_ATTACHMENT,
AVMEDIA_TYPE_NB
};
static int wanted_stream[AVMEDIA_TYPE_NB]={
[AVMEDIA_TYPE_AUDIO]=-1, // Line 234
[AVMEDIA_TYPE_VIDEO]=-1,
[AVMEDIA_TYPE_SUBTITLE]=-1,
};
but g++ throws the following error
playerthread.cpp:234: error: expected primary-expression before '[' token
What's the issue here?
These kind of designated initializers aren't supported by g++, but they are by gcc. I'm not certain it's allowed in the C++ standard at all. You can see the same if you bring the code down to a very simple:
int array[10] = { [1] = 5 };
It's fine in C, not C++.
Related
I would like to have compiler throw an error every time there is a declaration after statement because that is the coding style I want to enforce, but I also want to compile with -std=c99 since I use some of the specific c99 features.
The problem is that in c99 declarations are allowed anywhere in the code, not just at the beginning of a block.
Take a look at the following program:
// prog.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
int i = 0;
return 0;
}
If I compile this code with gcc like this:
gcc -std=c99 -Werror=declaration-after-statement prog.c
it throws the following error:
prog.c: In function ‘main’:
prog.c:6:9: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
6 | int i = 0;
| ^~~
cc1: some warnings being treated as errors
This is the behavior I would like to have when compiling with clang, but clang behaves differently.
If I compile the same code with clang like this:
clang -std=c99 -Werror=declaration-after-statement prog.c
it throws no errors.
Only if I compile the code with clang like this it throws the error I want:
clang -std=c90 -Werror=declaration-after-statement prog.c
prog.c:6:6: error: ISO C90 forbids mixing declarations and code [-Werror,-Wdeclaration-after-statement]
int i = 0;
^
1 error generated.
But this is not good for me because I need to use -std=c99.
Is it possible to force -Werror=declaration-after-statement along with -std=c99 when compiling with clang?
Looking at the source code of clang it seems like not supported.
The diagnostic is defined in clang/include/clang/Basic/DiagnosticSemaKind.td
def ext_mixed_decls_code : Extension<
"ISO C90 forbids mixing declarations and code">,
InGroup<DiagGroup<"declaration-after-statement">>;
And its only usage is in clang/lib/Sema/SemaStmt.cpp
StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
// Note that __extension__ can be around a decl.
unsigned i = 0;
// Skip over all declarations.
for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
// We found the end of the list or a statement. Scan for another declstmt.
for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
if (i != NumElts) {
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
Diag(D->getLocation(), diag::ext_mixed_decls_code); // <-- here
}
}
...
Note the !getLangOpts().C99 in the if. The diagnose code will never execute with a standard above c90.
Well one thing you can surely try is build clang by yourself and delete that part of the if so end up with if (!getLangOpts().CPlusPlus).
I tried and it worked for me.
You can configure the clang build with cmake -G "Ninja" -DCMAKE_BUILD_TYPE="Release" -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_C_COMPILER="/usr/bin/gcc" -DCMAKE_CXX_COMPILER="/usr/bin/g++" -DLLVM_PARALLEL_LINK_JOBS=2 -DLLVM_OPTIMIZED_TABLEGEN=ON path/to/llvm-project/llvm
I'm writing a simple code in C language, and this works.
Which compiles and excutes with no errors, gives the expected output.
#include <stdio.h>
int main(void) {
struct SiteTemplate {
int views;
};
int visit(struct SiteTemplate *site) {
site -> views++;
return 0;
}
struct SiteTemplate site;
site.views = 0;
visit(&site);
printf("%d\n", site.views);
return 0;
}
But in my VS Code, with C_Cpp linting is on, my IDE shows the following error and other problems with it.
declaration is incompatible with previous "visit" (declared at line 8)
Having a screenshot of it:
This error linting is really confusing me since my code works with gcc, it doesn't show any error when compiling.
And also, if I move my struct and function definition to the global level instead of inside main(), then the errors don't exist anymore... But what's the error declaration is incompatible? Or is there any problem with my code?
Click here to view the another screenshot to save whitespaces of this page.
By the way, the version of my VS Code is 1.52.0, with default C_Cpp linting.
Nested function definition is not standard C, it's supported by compiler extensions. According to C standard, any function definition needs to appear outside of any other function definition.
Compiling with gcc -std=c99 -Wextra this piece of code:
#include <stdio.h>
struct T {
int a;
int *b;
int c;
};
int main(void)
{
struct T t = {.b = ((int []){1, 1})};
printf("%d\n", t.b[1]);
return 0;
}
Is giving me a warning:
demo.c:11:12: warning: missing initializer for field ‘c’ of ‘struct T’ [-Wmissing-field-initializers]
struct T t = {.b = ((int []){1, 1})};
^
demo.c:6:9: note: ‘c’ declared here
int c;
^
But designated initializers are supposed to initialize to zero the rest of the members even if they are ommited.
Why the warning? (clang compiles the same piece of code without warnings)
gcc version 6.3.0 20170516 (Debian 6.3.0-18)
clang version 3.8.1-24 (tags/RELEASE_381/final)
It looks like a gcc "consistency bug", here is the relevant code snippet in gcc/c/c-typeck.c
7436 /* Warn when some struct elements are implicitly initialized to zero. */
7437 if (warn_missing_field_initializers
7438 && constructor_type
7439 && TREE_CODE (constructor_type) == RECORD_TYPE
7440 && constructor_unfilled_fields)
7441 {
7442 bool constructor_zeroinit =
7443 (vec_safe_length (constructor_elements) == 1
7444 && integer_zerop ((*constructor_elements)[0].value));
7445
7446 /* Do not warn for flexible array members or zero-length arrays. */
7447 while (constructor_unfilled_fields
7448 && (!DECL_SIZE (constructor_unfilled_fields)
7449 || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
7450 constructor_unfilled_fields = DECL_CHAIN (constructor_unfilled_fields);
7451
7452 if (constructor_unfilled_fields
7453 /* Do not warn if this level of the initializer uses member
7454 designators; it is likely to be deliberate. */
7455 && !constructor_designated
7456 /* Do not warn about initializing with ` = {0}'. */
7457 && !constructor_zeroinit)
7458 {
7459 if (warning_at (input_location, OPT_Wmissing_field_initializers,
7460 "missing initializer for field %qD of %qT",
7461 constructor_unfilled_fields,
7462 constructor_type))
7463 inform (DECL_SOURCE_LOCATION (constructor_unfilled_fields),
7464 "%qD declared here", constructor_unfilled_fields);
7465 }
7466 }
The intent of the code appears to be to warn if any attribute constructor has an unfilled-field. The fact that you are not getting a warning on element 'a' is likely the "consistency bug" here.
If -Wextra is intended to turn on the missing initializers warning, then it has. The question is, should the "missing initializers warning" exclude omitted attributes? It seems that gcc and clang disagree about this - and it might be fine for them to?
This may not be the answer you are looking for .. but hope it helps with your understanding of the situation. :). GCC team has a consistency bug, but their code's intent seems to be warn in these cases, whereas clang, empirically, will not.
Why the warning?
Because -Wmissing-field-initializers is set by -Wextra and you set the latter in the gcc call.
-Wextra is picky, and -Wmissing-field-initializers is not even element of -Wall.
Omitting just some field initializers but not all is a source of error. In an array / struct with has some hundreds elements and you are just initializing some of them, then it's almost impossible for a human to grasp that by just looking at the code.
const EPGState* NewEPGState[] =
{
&bootupState,
&standbyState,
&watchtvState,
&guideState,
&settingsState,
&easState,
&diagnosticsState
};
What is wrong in this code? I am getting an error parse error before '*' token
Your answers will be appreciated.
Check which version of the compiler are you using , This code compiles well on
g++ version 4.1.2 20071124.
but fails when compiled with gcc
I assume you have defined class/struct EPGState correctly and all the variables used below are of same type i.e EPGState.
class EPGState
{
};
int main()
{
EPGState bootupState,standbyState;
const EPGState* NewEPGState[] =
{
&bootupState,
&standbyState
};
}
Are you getting "parse Error" at the compilation step or at run time.
This is not clear from the question.
I written some sample code to test.
#include<iostream>
int main()
{
int a;
int b;
int *ac[]={&a,&b};
return 0;
}
Above code fails on gcc and compiles on g++.
gcc version 4.1.2 20071124 (Red Hat 4.1.2-42)
/tmp/cc6829sJ.o: In function __static_initialization_and_destruction_0(int, int)':
test1.cpp:(.text+0x4f): undefined reference to std::ios_base::Init::Init()
You probaly have
struct EPGState
{
...
struct EPGState bootupState =
{
...
somewhere.
Then is shall be
const struct EPGState * NewEPGState[] =
{
&bootupState,
...
My current job at the university is to port a C program from MinGW (windows) to Visual Studio (nmake).
I have got a valid "makefile.vc" file for a very similar C program.
My approach was to adopt the Makefile (i.e. "makefile.vc") to the program I need to port.
All but four C files seem to compile fine. Those four files have various errors for example, syntax errors and "unknown size".
Should I continue with my approach to change the Makefile or use CMAKE instead of nmake?
Is there a tutorial or any other pointer on porting a C program from MinGW/gcc to nmake?
typedef struct {
A_TypeConverter *converter;
char *domain;
} enumeratorConverterEntry;
static enumeratorConverterEntry enumeratorConverterEntries[]; /* line 186 */
error:
f.c(186) : error C2133: 'enumeratorConverterEntries' : unknown size
typedef struct AsmInstructionInfo {
int flags;
CONST char **argTypes; /* line 7 */
int minArgs;
int maxArgs;
int cArgs;
} AsmInstructionInfo;
error:
fAssemble.c(7) : error C2061: syntax error : identifier 'CONST'
..
/* file fStack.c: */
#ifdef CHECK_ACTIVATION_COUNTS
/* code */
#endif
/* more code */
void fShowStack(l_Interp *interp) { /* line 94 */
l_CallFrame *framePtr;
/* more code */
error:
fStack.c(94) : error C2143: syntax error : missing ')' before '*'
fStack.c(94) : error C2143: syntax error : missing '{' before '*'
fStack.c(94) : error C2059: syntax error : ')'
fStack.c(94) : error C2054: expected '(' to follow 'interp'
static enumeratorConverterEntry enumeratorConverterEntries[]; /* line 186 */
That looks like a valid incomplete, forward declaration of an array, which would be valid syntax, except I think for the static qualifier. I don't have a copy of the 'C' standard in front of me, but reading between the lines on the results of Googling "forward declaration of static array" seems to indicate that an incomplete definition of a static array results in undefined behavior, so Microsoft and GNU are legitimately entitled to do whatever they want with it. GNU accepts it, and Microsoft rejects it. As Mark Wilkins points out you should be make the Microsoft compiler happy by replacing it with:
extern enumeratorConverterEntry enumeratorConverterEntries[]; /* line 186 */
In general it's worth noting that the Microsoft compiler only supports the C89 standard, while the GNU compiler supports portions of the C99 standard, and several of their own extensions, depending on the arguments to the compiler.
The errors in fAssemble.c and fStack.c look like one or more preprocessor files are missing or incomplete. You should search your source to find out where CONST and l_Interp are defined, and then figure out why they are not being picked up in the files where the errors are occurring.
I just now tried out that array declaration with MinGW, and it does compile. To make it link, though, it needs the array to be defined elsewhere. The result is that it appears to be the same as the extern storage class:
extern enumeratorConverterEntry enumeratorConverterEntries[];
I'm not sure if there are other subtleties associated with the original declaration using a static storage class for the global.