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).
Related
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.
EDIT: problem explained more in depth here (thank you #Eric Postpischil). It seems to be a bug in GCC.
First, let me start with some context: the code I'm writing is using an API I can't change, on a GCC version I can't change, with compilation flags I'm not allowed to remove, and when I'm done with it must have precisely zero warnings or #pragmas.
EDIT: no unions either.
EDIT2: assume the build system also uses -Wall -ansi -pedantic and every other warnings under the sun.
I'll confirm the GCC version tomorrow but I'm fairly certain it's not above GCC 7. In the meantime I'm testing with GCC 6.3.
EDIT3: I'm marking the issue as 'answered'. For completeness' sake, I'm adding some more information below:
I've checked the compiler version being used, and it's not pretty. We're using Mingw and a gcc.exe --version tells me it's GCC 3.4.5.
Furthermore, compilation flags include wall wextra wcast-qual wpointer-arith wconversion wsign-conversion along with others that are not relevant to the problem at hand.
The problem
Consider the following code:
#include "stdio.h"
#include "stdint.h"
typedef uint32_t MyType[4];
const MyType* foo(const uint8_t* a)
{
return (const MyType*) a;
}
void myapi_foo(const MyType* d) {}
int main()
{
uint8_t a[4*sizeof(uint32_t)];
const MyType* b = foo((const uint8_t*) a);
myapi_foo(b);
return 0;
}
Compiled with GCC and the -Wcast-qual flag, this code will throw the following warning:
warning: cast discards ‘const’ qualifier from pointer target type [-Wcast-qual]
return (const MyType*) a;
EDIT: to clarify, the error is on this line:
return (const MyType*) a;
The cause of the problem
I know the root cause of the problem is the typedef type MyType which is in fact an array. Sadly, I do not have the luxury of modifying this typedef, nor the API function myapi_foo and its dubious choice of parameter type.
To be honest, I don't really understand why is the compiler so unhappy about this cast, so clarifications are more than welcome.
The question
What would be the cleanest way of indicating to the compiler everything should be treated as a pointer to const data?
Discarded and potential solutions
Here are a few 'solutions' that I have found but left me unsatisfied:
Remove the -Wcast-qual flag. I cannot do that due to code quality rules.
Add a #pragma to turn off the warning around that part of the code (as shown here). Similarly I'm not allowed to do that.
Cast the pointer to an integer, then cast back to a pointer (as shown here) return (const MyType*) (uint32_t) a;. It's very crude, but using uint32_t as memory addresses has precedent in this project so I might have to use it as a last ditch effort.
EDIT: #bruno suggested using an union to side-step the problem. This is a portable and fairly elegant solution. However, the aforementioned code quality rules downright bans the use of unions.
EDIT: #Eric Postpischil and #M.M suggested using a (const void*) cast return (const void*) a;, which would work regardless of the value of sizeof(MyType*). Sadly it doesn't work on the target.
Thank you for your time.
This is GCC bug 81631. GCC fails to recognize the cast to const MyType * retains the const qualifier. This may be because, in this “pointer to array of four const uint32_t”, GCC performs a test of whether the array is const whether than of whether the array elements are const.
In some GCC versions, including 8.2, a workaround is to change:
return (const MyType*) a;
to:
return (const void *) a;
A more drastic change that is likely to work in more versions is to use:
return (const MyType *) (uintptr_t) a;
Note About Conversion and Aliasing:
It may be a problem that this code passes a to a function that casts it to const MyType *:
uint8_t a[4*sizeof(uint32_t)];
const MyType* b = foo((const uint8_t*) a);
In many C implementations, MyType, being an array of uint32_t, will require four-byte alignment, but a will only require one-byte alignment. Per C 2018 6.3.2.3 6, if a is not correctly aligned for MyType, the result of the conversion is not defined.
Additionally, this code suggests that the uint_t array a may be used as an array of four uint32_t. That would violate C aliasing rules. The code you show in the question appear to be a sample, not the actual code, so we cannot be sure, but you should consider this.
You can do that :
const MyType* foo(const uint8_t* a)
{
union {
const uint8_t* a;
const MyType* b;
} v;
v.a = a;
return v.b;
}
w.c being your modified file :
pi#raspberrypi:/tmp $ gcc -pedantic -Wall -Wcast-qual w.c
pi#raspberrypi:/tmp $
That works whatever the compiler (no #pragma) or the respective size of int and pointer(no cast between int and pointer), but I am not sure this is very elegant ;-)
It is strange to have that foo function and at the same time compile with Wcast-qual, it's contradictory
Edit, If you cannot use union you can also do that
const MyType* foo(const uint8_t* a)
{
const MyType* r;
memcpy(&r, &a, sizeof(a));
return r;
}
Compilation :
pi#raspberrypi:/tmp $ gcc -pedantic -Wall -Wcast-qual w.c
pi#raspberrypi:/tmp $
If nothing works, you might like to use the uintptr_t hammer, if the implmentation provides it. It is optional by the C11 Standard:
const MyType* foo(const uint8_t* a)
{
uintptr_t uip = (uintptr_t) a;
return (const MyType*) uip;
}
Upon linking some code that performs division and modulo operations on an integer of type long long I receive the following two errors:
util.c:(.text+0x1af): undefined reference to '__divdi3'
util.c:(.text+0x1ef): undefined reference to '__moddi3'
I have also tried using unsigned long long, however that results in the following error:
util.c:(.text+0x1af): undefined reference to '__udivdi3'
util.c:(.text+0x1ef): undefined reference to '__umoddi3'
Replacing the long long with int or long fixes the problem, but I need to use unsigned long long.
I am using the following command line to compile and link the program:
gcc -ffreestanding -c kernel/util.c -o kernel/util.o
ld -o kernel32.bin -Ttext 0x500 kernel/util.o kernel/kernel.o --oformat binary
and this is the function:
char* itoa(unsigned long long i, char b[]){
if (i == 0){
b[0] = '0';
b[1] = '\0';
return b;
}
char const digit[] = "0123456789";
char* p = b;
if (i < 0){
*p++ = '-';
i *= -1;
}
unsigned long long shifter = i;
while (shifter){
++p;
shifter = shifter / 10;
}
*p = '\0';
while (i){
*--p = digit[i % 10];
i = i / 10;
}
return b;
}
Clearly, the compiler is referencing __udivdi3 to divide the integer but the linker can't find it..
By the way, the binary is to be used as a 32 bit operating system and therefore lacks many standard libraries
EDIT: I am using gcc 4.8.4 and ld 2.24
When building code for an architecture that does not provide hardware support for the data type GCC uses as [unsigned] long long, GCC generates code for arithmetic operations on values of that type that involves calling functions provided by its own support library, libgcc. The __divdi3() etc. are among those. This is not the only way GCC could do it, but it is well suited to GCC's aim of supporting many architectures.
When instructed to act as a freestanding compiler, GCC does not automatically link libgcc, with the result that no implementation of these functions is automatically provided. This has been the subject of previous complaints, such as this one and this later one. The GCC maintainers take the position that this is not a GCC flaw, and that it does not render GCC non-conforming. I find their reasoning questionable, but it's unlikely to change. At minimum, this is a quality of implementation issue.
I do see where the GCC maintainers are coming from, however: a freestanding environment provides next to none of the standard library, and must not interpret most function calls except according to the code presented to it. What, then, if that code contains explicit calls to functions with the same names as some of those in libgcc? Unless the user explicitly says he wants libgcc, the compiler should not assume that it is those versions of the functions that are wanted. The problem, though, is that if the compiler inserts such calls, then not only does it know which implementations are intended, but the result is wrong if an incompatible one is linked instead. Thus, this is a problem of GCC's own making.
The bottom line is that you can explicitly request that libgcc be linked. You will want to specify that it be linked statically, as you cannot rely on a dynamic linker in your context. These additional link options should do it:
-static-libgcc -lgcc
Alternatively, you could write your own implementations of those functions, or crib the source from GCC, but I don't see why you would prefer either of those options.
Per this link: https://gcc.gnu.org/onlinedocs/gcc-3.3/gccint/Library-Calls.html
the functions of interest are defined in the libgcc.a library. (not in the libgcc.so library.)
I think your code will use the libgcc.a library if your link step contains the -static parameter
However, this link: https://sourceware.org/ml/crossgcc/2006-04/msg00000.html
has the following to say:
Typically you link with gcc instead of ld to avoid just these types of problems.
I would either change it to link using gcc, or add the proper -L and -l options to get it to use the proper libgcc
It seems that you are using the wrong function:
— Runtime Function: long __divdi3 (long a, long b)
I guess that the correct function is:
— Runtime Function: long long __divti3 (long long a, long long b)
(https://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines)
Unfortunately I'm not sure if is implemented in your gcc version.
I'm rewriting some Mac code that embeds a freeware library originally written in C. The compiler is complaining that since I'm using long double, I should use fabsl rather than fabs. So I went and changed them.
However, reading a few pages on the topic it seems that there should be no difference, that ever since C99, there is a type generic macro that inserts the correct call based on type.
So perhaps I am using the wrong dialect?
Does anyone know what the Compiler Default is in xcode7, and whether it has the generic macro?
The generic macro is defined in <tgmath.h>, so you need to #include it, as shown in the following snippet:
#include <tgmath.h>
#include <stdio.h>
int main() {
long double ld = 3.14;
double d = 3.14;
float f = 3.14f;
printf("%Lf %lf, %f\n",fabs(ld), fabs(d), fabs(f));
return 0;
}
It compiles flawlessly with
gcc -Wall -Wextra a.c -oa -std=c99
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.