Code:
char *color_name[] = {
"red",
"blue",
"green"
};
#define color_num (sizeof(color_name)/sizeof(char*))
int main(){
printf("size %d \n",color_num);
return 0;
}
It works fine with GCC 4.8.2 on Centos 7.
But I got error running above program on mac which says:
note:expanded from macro 'color_num'
Compiler on my Mac:
……include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix
I've been told that GCC has been linked to Clang on Mac when it is used to compile program, am I right?
Qestion:
So why does Clang report that error? Is that concerning pre-processing?
And if I do this, it works fine:
int a = color_num;
printf("%d\n",a);
or:
printf("%d\n",sizeof(color_num)/sizeof(char*));
UPDATA=============
Crayon_277#Macintosh 20150525$ gcc -g -o ex11 ex1.c
ex1.c:16:21: warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
printf("size %d\n",color_num);
~~ ^~~~~~~~~
%lu
ex1.c:14:19: note: expanded from macro 'color_num'
#define color_num (sizeof(color)/sizeof(char*))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
It seems no error but just that format warning.
I think it may concerning the extension I use for vim
scrooloose/syntastic
I got error from that:
It is probably complaining that the expression expanded from color_num is an unsigned (perhaps unsigned long) while the format in the printf is a signed integer.
sizeof gives size_t, which is always an unsigned type, as noted in is size_t always unsigned?, but the number of bits depends on the implementation. Compiler warnings may — and often do — refer to the mismatch in terms of the equivalent type rather than size_t as such. The C standard after all, does not specify the nature of diagnostic messages.
When you changed that to an assignment, it is less strict, since that is a different check.
The "note" lines are something that the compiler adds to a warning/error message to help you understand where the problem came from.
(As the comment notes, you should quote the entire warning message, to make the question understandable).
The sizeof gives the value with size_t type, the right format specifier for size_t is "%zu".
Related
Should scanf("%ms", &s) work in clang?
app.c:
#include <stdlib.h>
#include <stdio.h>
int main() {
char *s;
int ret = scanf("%ms", &s);
if (ret) {
printf("%d %s\n", ret, s);
free(s);
}
else {
printf("NO!\n");
}
}
$ clang ./app.c && echo abc | ./a.out
NO!
$ clang --version
Apple clang version 12.0.5 (clang-1205.0.22.11)
Same results with the gcc installed on my macOS, but it seems to using clang internally.
On Linux using gcc, scanf succeeded:
1 abc
From gcc man scanf:
Each conversion specification in format begins with either the
character '%' or the character sequence "%n$" (see below for the
distinction) followed by:
- An optional 'm' character. This is used with string
conversions (%s, %c, %[), and relieves the caller of the
need to allocate a corresponding buffer to hold the input:
instead, scanf() allocates a buffer of sufficient size,
and assigns the address of this buffer to the
corresponding pointer argument, which should be a pointer
to a char * variable (this variable does not need to be
initialized before the call). The caller should
subsequently free(3) this buffer when it is no longer
required.
This is confusing because if I break the type by removing the second arg & then clang gives a warning; it recognizes that %ms needs a pointer to a char*:
./app.c:5:28: warning: format specifies type 'char **' but the argument has type 'char *' [-Wformat]
int ret = scanf("%ms", s);
~~~ ^
%s
Compiler is not the C standard library. It's way more diversified. clang, gcc, msvc and others are compilers. glibc, musl and others are C standard library implementations, and they come with scanf() function implementation and may or may not support %m assignment-allocation character extension. The %m is non-standard, as in it is not specified in the C language standard.
Does clang support format string %ms so scanf() allocates the buffer?
clang is a compiler, it compiles code. In a literal sense of the question, clang supports passing anything to scanf() function, including any format specifiers. clang compiles the code and creates an executable.
As you also found out, clang as a compiler supports diagnosing the case, when an invalid parameter type is provided for %ms scanf format specifier. In that sense, clang warnings support this format specifier.
Let's say, the question "if clang supports %m specifier" is like asking if a car tire can drive fast. Well, literally it can, but it depends on the engine (the C standard library) if your car will be fast or not (support the specifier or not). (Bad allegory, but hope it just illustrates the point of the answer).
on my macOS
As I understand, the BSD libc C standard library implementation is used on macOS. As you found out, this implementation of scanf() function does not support m extension.
The m extension was most probably first implemented in GNU C library. I see it was added in Issue 7 to POSIX scanf specification.
Even though the compiler warning recognizes the %ms syntax, the compiled code does not support it.
Running man scanf the BSD manual doesn't document the m character.
I have the following small C-programm (main.c):
#include <stdio.h>
int main() {
printf("bmi %.1f \n", bmi(85, 1.5f));
return 0;
}
float bmi(int weight, float height) {
return weight / (height * height);
}
Why does it compile without error? I expected that I need a prototype of the bmi()-function before the main().
When I debug the program, height is 0.0 not 1.5! What's going on?
Why does it compile without error?
The C language used to allow implicit declarations prior to the C99 standard, and VS defaults to that behavior. However, with the default settings, VS does issue the following warnings, which should not be ignored.
(4,30): warning C4013: 'bmi' undefined; assuming extern returning int
(4,12): warning C4477: 'printf' : format string '%.1f' requires an argument of type 'double', but variadic argument 1 has type 'int'
You can promote C4013 to an error (/we"4013") in which case the compilation will actually fail instead of issuing just a warning. In recent versions 16.8 and later compiling with /std:c11 should disable implicit declarations and always trigger an error (disclaimer: not tried).
When I debug the program, height is 0.0 not 1.5! What's going on?
At the point the compiler sees the bmi(85, 1.5f) call, it will assume the implicit function declaration int bmi(). In particular, it will assume the return value is an int so it will pass it as an int to printf. But the format string "%.1f" tells printf to expect a double argument (following the default promotion rules), so what happens next is undefined behavior.
After developing a new firmware (main and libraries) with CCS for my CC2538, all errors are debugged, and now, device is working fine.
As from CCS I can not flash the firmware permanently, I'm working with IAR to develop this action.
On IAR, I have created the workspace, the project and included all libraries and files needed to compile the firmware. But, compilation fails due to incompatible types errors.
Error[Pe144]: a value of type "int" cannot be used to initialize an
entity of type "signed short *"
int16_t *accData[3] = malloc(sizeof(int16_t));
Error[Pe513]: a value of type "int" cannot be assigned to an entity
of type "signed short *"
int16_t *accData[3] = malloc(sizeof(int16_t));
Error[Pe120]: return value type ("signed short **") does not match
the function type ("signed short*")
int16_t * lsm303d_readAccData(void)
{
int16_t *accData[3] = malloc(sizeof(int16_t));
...
return accData;
}
Which is the root cause of these errors?
Maybe, any option of the compiler? Do I need to add any file? Or prototype on the code?
KR!
Which is the root cause of these errors?
"a value of type "int"" is the root cause. There should be no int here! Just the signed short* (which is your int16_t*) and a void* from malloc.
This is because you are using a C90 compiler and forgot to #include <stdlib.h>. Upon finding a function with no prototype, C90 would implicitly assume you want a function returning int, which explains the compiler errors "a value of type "int"". But malloc actually returns a void*, so this is a severe bug. Solve this by including the header stdlib.h where malloc is found.
This undesired and irrational behavior of the language was fixed 17 years ago. Consider using a modern compiler instead, or configure your compiler to use the current C language standard (ISO 9899:2011).
That being said, this code doesn't make any sense either:
int16_t *accData[3] = malloc(sizeof(int16_t));
You probably meant
int16_t *accData = malloc( sizeof(int16_t[3]) );
The first error is somewhat misleading. It seems to indicate that you forgot to include <stdlib.h>, so malloc is undefined and the compiler assumes it returns int.
In any case, you are assigning a pointer to an array: this is incorrect.
Returning the address of a local automatic array is incorrect too.
You should define accData as a pointer instead of an array, and make it point to an allocated array of int16_t. You seem to want this array to hold 3 elements, otherwise modify the code accordingly:
#include <stdlib.h>
int16_t *lsm303d_readAccData(void) {
int16_t *accData = malloc(sizeof(int16_t) * 3);
...
return accData;
}
You should configure the compiler to issue more warnings and refuse obsolete constructions such as implicit int. For gcc, add -std=c99 or -std=c11 and -Wall -Wextra -Werror.
In writing an emulator, I am using a lot of various large unsigned constants, and, hence, on compilation receive a very large number of warnings of the form:
warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
making it difficult to debug the rest of the program. I understand that this can be suppressed with a pragma:
#pragma GCC diagnostic ignored "-W...."
But I am not sure which kind of warning this falls into and don't want to disable "-Wall" in case there are other more important warnings.
What is the smallest subset of warnings that can be disabled to remove this warning?
EDIT: As requested, one of the functions that trigger the message:
void NAND(unsigned int *to_return, unsigned int r1_value, unsigned int r2_value){
unsigned int result = (r1_value & r2_value) ^ 4294967295;
to_return[0] = result;
to_return2] = 0;
}
Specifically, the 4294967295 constant.
This was compiled under:
gcc -O3 "C source\Hard Disk Version\CPU.c" -o CEmuTest.exe
on Windows (minGW).
The following program has undefined behavior:
#include <stdio.h>
int main(void)
{
unsigned int x = -100; // This is fine, becomes UINT_MAX - 100
printf("%d\n", x); // This is undefined behavior.
return 0;
}
C99 7.19.6.1p8 states %d expects an int argument.
C99 7.19.6.1p9 states "If any argument is not the correct type for the
corresponding conversion specification, the behavior is
undefined."
However, gcc -Wformat (which is included with -Wall) will not complain about the above program, why? Is this a bug, or a deliberate omission?
From the gcc manpage:
-Wformat
Check calls to "printf" and "scanf", etc., to make sure that the arguments supplied have types appropriate to the format string specified, and that the conversions specified in the format string make sense
My best guess is that the warning is skipped because the UB is arguably invoked by the value and not merely by the type. va_arg allows the signedness to mismatch as long as the value is representable in both the signed and unsigned type. However, printf and friends are not specified in terms of va_arg and the standard states that any type mismatch results in UB, but this is probably a bug in the standard. Otherwise, printf("%x",1); would invoke UB. See my question on the topic:
Does printf("%x",1) invoke undefined behavior?