_Alignas for struct members using clang & C11 - c

I'm having some trouble with -Wpadded using C11 and structs.
I've already read Structure member alignment with _Alignas, and I looked in the clang docs and saw that it IS supported now.
Also, I'm using a very new version of clang that I built from trunk recently.
$ clang --version
clang version 3.3 (trunk 175473)
Target: x86_64-unknown-linux-gnu
Thread model: posix
The problem I'm running into is this:
#include <stdlib.h>
#include <stdalign.h>
struct foo{
void* a;
int b;
};
int main() {
struct foo instance;
instance.a = NULL;
instance.b = 2;
return 0;
}
Which throws me this warning:
$ clang -Weverything -std=c11 t.c
t.c:4:8: warning: padding size of 'struct foo' with 4 bytes to alignment boundary [-Wpadded]
struct foo{
^
1 warning generated.
Now isn't this what _Alignas is for? I tried putting it before the int member declaration, like so:
struct foo{
void* a;
_Alignas(void*) int b;
};
But the same warning remains. I also tried putting the _Alignas in various places, to no avail. What am I missing here?
I know I could just ignore this particular warning and I understand why padding is important, so I'm not interested in workarounds or explanations about what padding is. I want to know how to change my C in a portable, standards conformant way so that the warning is no longer emitted.

-Weverything prints all diagnostic messages required by C as well as some diagnostics not required by C. The diagnostic that is printed here is not required by C: its purpose is informative and your program is already strictly conforming. C says an implementation is free to produce additional diagnostic messages as long as it does not fail to translate the program.

Related

Why can I use size_t without defining it?

int main(void)
{
size_t a = 20;
unsigned int b = 0;
b = a;
return 0;
}
no header files are included.
i wrote this in cmd
clang -std=c89 -W -Wall -pedantic-errors *.c
why does it compile and run without problems?
I am using clang 13.0.1. (LLVM-13.0.1-win32.exe)
linker is using VS
i don't know where to put this
"#error Compiled indeed"
The behavior you describe does not happen with clang on linux systems, but it does with the x64 version of MSVC as can be verified on the Godbolt compiler explorer.
It looks like size_t is a built-in type for this compiler.
The compiler accepts this built-in to be redefined as long as the definition is
typedef unsigned long long size_t;
Anything else causes an error. As commented by Jonathan Leffler, C11 and later allows you to define a typedef more than once as long as the definitions are the same (and not for a variably-modified type).

gcc struggling with struct foo_v1 : foo_v2 { a; };

my gcc (9.1.0) struggle with following structure definition
struct foo_v1 : foo_v2 { a; };
i guess it could be a matter of coding version such as ansi or c99.
reading 9.4.0 i could not find <struct a : b { c; };> notation.
please could anyone give me a hint where to find standard defining such a notation or how to compile with gcc.
have a great day
how to compile with gcc.
It is not valid C syntax. It is not possible to compile it with gcc as a C source code. It is also not a common extension in common C compilers.
It may be possible to compile the following with a C++ compiler (which makes the line compile-able after adding two lines and adding -xc++ to gcc):
struct foo_v2 { int stuff; };
#define a int variable
struct foo_v1 : foo_v2 { a; };
The presented line in the question, on its own, is not valid C++ code anyway.

"initialiser element is not constant" error in C, when using static const variable - Sometimes - Compiler settings?

I'm posting this because I couldn't find a suitable answer elsewhere, not because similar things haven't been asked before.
A project compiles just fine with the following:
#include <stdint.h>
void foo(void)
{ if (bar)
{ static const uint8_t ConstThing = 20;
static uint8_t StaticThing = ConstThing;
//...
}
}
But a cloned project does not, throwing the above error. Looks like we've not completely cloned compiler settings / warning levels etc, but can't find the difference right now.
Using arm-none-eabi-gcc (4.7.3) with -std=gnu99. Compiling for Kinetis.
If anyone knows which settings control cases when this is legal and illegal in the same compiler, I'm all ears. Thanks in advance.
Found the difference.
If optimisation is -O0 it doesn't compile.
If optimisation is -OS it does.
I'm guessing it produces 'what you were asking for, a better way' and fixes it.
Didn't see that coming. Thanks for your input everyone.
Converting some of my comments into an answer.
In standard C, ConstThing is a constant integer, but not an integer constant, and you can only initialize static variables with integer constants. The rules in C++ are different, as befits a different language.
C11 §6.7.9 Initialization ¶4 states:
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
§6.4.4.1 Integer constants defines integer constants.
§6.6 Constant expressions defines constant expressions.
…I'm not sure I understand the difference between a 'constant integer' and an 'integer constant'.
Note that ConstThing is not one of the integer constants defined in §6.4.4.1 — so, whatever else it is, it is not an integer constant. Since it is a const-qualified int, it is a constant integer, but that is not the same as an integer constant. Sometimes, the language of the standard is surprising, but it is usually very precise.
The code in the question was compiled by GCC 4.7.3, and apparently compiling with -O0 triggers the error and compiling with -Os (-OS is claimed in the question, but not supported in standard GCC — it requires the optional argument to -O to be a non-negative integer, or s, g or fast) does not. Getting different views on the validity of the code depending on the optimization level is not a comfortable experience — changing the optimization should not change the meaning of the code.
So, the result is compiler dependent — and not required by the C standard. As long as you know that you are limiting portability (in theory, even if not in practice), then that's OK. It's if you don't realize that you're breaking the standard rules and if portability matters, then you have problems of the "Don't Do It" variety.' Personally, I wouldn't risk it — code should compile with or without optimization, and should not depend on a specific optimization flag. It's too fragile otherwise.
Having said that, if it's any consolation, GCC 10.2.0 and Apple clang version 11.0.0 (clang-1100.0.33.17) both accept the code with options
gcc -std=c11 -pedantic-errors -pedantic -Werror -Wall -Wextra -O3 -c const73.c
with any of -O0, -O1, -O2, -O3, -Os, -Og, -Ofast. That surprises me — I don't think it should be accepted in pedantic (strictly) standard-conforming mode (it would be different with -std=gnu11; then extensions are deemed valid). Even adding -Weverything to the clang compilations does not trigger an error. That really does surprise me. The options are intended to diagnose extensions over the standard, but are not completely successful. Note that GCC 4.7.3 is quite old; it was released 2013-04-11. Also, GCC 7.2.0 and v7.3.0 complain about the code under -O0, but not under -Os, -O1, -O2, or -O3 etc, while GCC 8.x.0, 9.x.0 and 10.x.0 do not.
extern int bar;
extern int baz;
extern void foo(void);
#include <stdio.h>
#include <stdint.h>
void foo(void)
{
if (bar)
{
static const uint8_t ConstThing = 20;
static uint8_t StaticThing = ConstThing;
baz = StaticThing++;
}
if (baz)
printf("Got a non-zero baz (%d)\n", baz);
}
However, I suspect that you get away with it because of the limited scope of ConstThing. (See also the comment by dxiv.)
If you use extern const uint8_t ConstThing; (at file scope, or inside the function) with the initializer value omitted, you get the warning that started the question.
extern int bar;
extern int baz;
extern void foo(void);
#include <stdio.h>
#include <stdint.h>
extern const uint8_t ConstThing; // = 20;
void foo(void)
{
if (bar)
{
static uint8_t StaticThing = ConstThing;
baz = StaticThing++;
}
if (baz)
printf("Got a non-zero baz (%d)\n", baz);
}
None of the compilers accepts this at any optimization level.

struct issue probably related to codeblocks but I am not sure

While writing a simple program where I had to create structs for saving information about a film and a film director, both of those had the same variables inside but with different names
struct Regista
{
char nome[30];
char cognome[30];
int nascita;
int doIexist;
};
typedef struct Regista regista;
struct Film
{
char titolo[30];
char reg[30];
int anno;
int doIexist;
};
I had created an array for both and I wanted to pass those as argument in different functions in order to add elements in those array, and now the question I have: I wrongly wrote this:
int insertfilm(film arrayfilm[]);
int insertreg(regista arrayreg[]);
int main(){
//other stuff
film arrayfilm[SIZE];
regista arrayreg[SIZE];
//other stuff
switch (mainMenuChoice)
{
case 1:
{
insertfilm(arrayfilm);
break;
}
case 2:
{
insertreg(arrayfilm);
break;
}
//other stuff
it should be noted that i passed an array of struct film while it should expect an array of struct regista in insertreg()
I was expecting that it would report an error of wrong type but instead it went all silent and run it without any problem.
My question is: is this caused by my IDE (codeeblocks) or by the C implementation?
The gcc/mingw compiler that Codeblocks uses by default is lax when it comes to give compiler errors for C language type compatibility violations. If you run it with default settings, you get:
warning: passing argument 1 of 'insertreg' from incompatible pointer type
Now as far as the C language is concerned, the above is sufficient for the compiler to be compliant. C doesn't speak of errors and warnings, only of diagnostic messages.
Your code is not valid C, since two structs are only compatible if they have the same struct tag, if all their members have the same type and if they have the same variable name. You use different struct tags and different variable names both, so they aren't compatible.
Formally, since the types aren't compatible, your code is a "constraint violation of the simple assignment rule" and a compiler must give you a diagnostic message, which it did.
I strongly recommend all beginners to compile with strict standard compliance and maximum warnings though. With gcc this means -std=c11 -pedantic-errors -Wall -Wextra. Pedantic errors in particular will block the code from compiling into an executable even though there are C language violations.
In Codeblocks specifically: go Settings -> Compiler, then check the corresponding options there, for example "Enable extra compiler warnings [-Wextra]" to enable -Wextra.

Union Zero Initialization with clang vs gcc

Given the following C code:
union Test {
struct {
int f1;
int f2;
};
struct {
int f3;
int f4;
int f5;
};
};
union Test test = {.f1 = 1, .f2 = 2};
When I compile this with gcc 6.1.1 f5 will be zero initialized. When I do with clang 3.8.0 it is not. I tried with -O0 and -O2 for both compilers which did not make any difference. This is on Linux x64.
Which is the correct behavior and can I tell clang to behave like gcc in this case? Reason is I try to compile some code with clang that assumes zero initialization in this case.
Update
Since the answers so far cite C11. Were there any changes in the standard that changed the behavior in later versions?
C11 specifies at section 6.2.6.1.7 :
When a value is stored in a member of an object of union type, the bytes of the object
representation that do not correspond to that member but do correspond to other members
take unspecified values.
You access the union via the first struct, accessing members of the second struct can produce unspecified values, so clang is not wrong neither is gcc.
Update: anonymous members were added in C11. Designated inits appeared in C99.

Resources