I am wondering why I can't compile an example from book. I simplify the example here to avoid posting example from a copyrighted book.
#include <stdio.h>
BYTE *data = "data";
int main()
{
printf("%s", data);
return 0;
}
When compile with g++, i get error,
error: invalid conversion from 'const char*' to 'BYTE*'
The program works by simply replacing BYTE with char, but I must be doing something wrong since the example comes from a book.
Please help pointing out the problem. Thanks.
BYTE isn't a part of the C language or C standard library so it is totally system dependent on whether it is defined after including just the standard stdio.h header file.
On many systems that do define a BYTE macro, it is often an unsigned char. Converting from a const char* to an unsigned char* would require an explicit cast.
Related
I'm learning C in school and am doing some input and string comparisons and am running into what looks like a casting issue.
Here is my code:
size_t unit_match_index(char *userInput) {
char* unit = malloc(strlen(userInput) + 1);
strcpy(unit, userInput);
//convert to lowercase
for (size_t i = 0; i < strlen(unit); ++i) {
unit[i] = tolower(unit[i]);
/*C6385: invalid data from 'unit': the readable size is 'strlen(userInput)+1' bytes, but 2bytes may be read
C6386: buffer overrun while writing to 'unit': the writable size is [same as above]
*/
}
//...
}
After doing a little bit of research, it looks like tolower() looks for an int and returns an int (2 bytes), and thinks strlen(userInput)+1 may equate to 1, making the total unit array size only 1 byte.
Is there something I should be doing to avoid this, or is this just the analyzer being a computer (computers are dumb)? I'm concerned because I will lose marks on my assignment if there are errors.
As suggested in an answer to this related question, these two warnings are caused by a "bug" in the MSVC Code Analyser.
I even tried the 'fix' I suggested in my answer to that question (that is, using char* unit = malloc(max(strlen(userInput), 0) + 1);) – but it didn't work in your code (not sure why).
However, what did work (and I have no idea why) is to use the strdup function in place of your calls to malloc and strcpy – it does the same thing but in one fell swoop.
Adding the casts (correctly)1 suggested in the comments, here's a version of your code that doesn't generate the spurious C6385 and C6386 warnings:
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
size_t unit_match_index(char* userInput)
{
char* unit = strdup(userInput);
//convert to lowercase
for (size_t i = 0; i < strlen(unit); ++i) {
unit[i] = (char)tolower((unsigned char)unit[i]);
}
//...
return 0;
}
However, MSVC will now generate a different (but equally spurious) warning:
warning C4996: 'strdup': The POSIX name for this item is deprecated.
Instead, use the ISO C and C++ conformant name: _strdup. See online
help for details.
As it happens, the strdup function (without the leading underscore) is adopted as part of the ISO Standard since C23 (6/2019).
1 On the reasons for the casts when using the tolower function, see: Do I need to cast to unsigned char before calling toupper(), tolower(), et al.?. However, simply adding those casts does not silence the two code analysis warnings.
I am programming a Teensy micro-controller as a part of a C course and am trying to work out the value of one of my integer variables. I have an integer variable called Contrast, which is initialised to the value of a constant defined as a hexadecimal number at the beginning of the .c file:
#define LCD_DEFAULT_CONTRAST 0x3F
int Contrast = LCD_DEFAULT_CONTRAST;
I am trying to investigate how this Contrast value is stored and displayed, if it shows up as 63 or 0x3F, and if they are interchangeable. I tried to use:
printf("%d", Contrast);
to print out the Contrast value to the terminal and I got the error implicit declaration of function 'printf'. I thought printf() was part of the built-in C library, so I am confused why this is not working.
Can anyone please tell me how I print the value of this variable to the screen?
The implicit declaration error just means your compiler proper doesn't have a declaration for printf. Unless you're also getting a linker error, the linker (linking usually follows compilation, unless you pass -c to disable it) is probably slapping the standard lib right on, in which case you can simply solve your warning by including stdio.h or less preferably by declaring int printf(char const*, ...);.
If you trully don't have the standard lib, you'll need to convert the integer to a string manually with something like:
int n = 42;
char buf[20];
char *end = buf+(sizeof(buf)-1), *p = end;
*p--=0;
if(n==0) *p=='0';
else{
while(n){
printf("%d\n", n%10);
*p--=n%10+'0';
n/=10;
}
p++;
}
and then pass it to your system's raw IO routine for which you'll need to have set up the system-entering assembly.
If you don't have a system, it'd be even more technical, and you probably wouldn't be asking this question.
printf() is declared in standard library header <stdio.h>.
You have to #include <stdio.h> to use printf(). It is a library call, much like all other library calls in C..
Please read until the end before you say: "Oh no, this question again..."
I am right now seating in a C course and the following example has been provided in course book:
#include <stdio.h>
#include <stdint.h>
void Terminal_PrintData(uint16_t * const Data);
int main(void){
uint16_t StringData[] = "MyData";
Terminal_PrintData(StringData);
}
void Terminal_PrintData(uint16_t * const Data)
{
printf("Value: %s", *Data);
}
When I compile this masterpiece, this is what I get:
F:\AVR Microcontroller>gcc -o test test.c
test.c: In function 'main':
test.c:7:26: error: wide character array initialized from non-wide string
uint16_t StringData[] = "MyData";
My questions are:
Is it correct to declare a string with uint16_t?
What is recommended way to pass a string to a function?
Your immediate questions:
Is it correct to declare a string with uint16_t?
No.
All strings are always char[]. There ar also wide strings (strings of wide characters), which have the type wchar_t[], and are written with an L prefix (e.g. L"hello").
What is recommended way to pass a string to a function?
As a pointer to the first character in the string, so either char * or wchar_t *. The const qualifier makes no sense here; it would mean that the pointer (not the string itself) is constant (see here). I'd recommend writing wchar_t const * or const wchar_t * instead; it has a different meaning (i.e. the string can't be changed), but it's correct and meaningful.
You mention that this code is from a course book. I'm not sure whether you mean that these are lecture notes handed out by your professor, or whether you bought a published book. In either case, if this snippet is representative of the quality of the book/notes, get a refund.
For now, let's make this code work.
There's an error in this code that will cause the program to crash:
printf("... %s ...", ..., *string, ...) when string is a char* is always wrong. Don't dereference that pointer.
If you insist on using "wide" characters (which is questionable), you're going to have to change a few things:
Rather than using char, you need to include <wchar.h> and use wchar_t instead. As far as I know, uint16_t and uint8_t won't work unless you use explicit casting everywhere. That's because char doesn't have 8 bits, but CHAR_BIT bits.
Wide character literals must start with an L prefix.
Rather than using printf, you need to use wprintf.
In the format string, use %ls rather than %s. (Unless you use Microsoft's compiler.)
Finally, some less grave errors:
As noted, T * const arguments are useless. The author probably meant T const * (or equivalently const T *).
You can remove <stdint.h> and <stdio.h>. We're no longer using uint16_t, and <wchar.h> declares some wide character <stdio.h>-like functions.
I end up with the following code:
#include <wchar.h>
void Terminal_PrintData(wchar_t const * Data);
int main(void){
wchar_t StringData[] = L"MyData";
Terminal_PrintData(StringData);
}
void Terminal_PrintData(wchar_t const * Data)
{
wprintf(L"Value: %ls", Data);
}
This compiles and runs as expected with both GCC and Clang on Linux x86-64.
There are two kinds of strings: "non-wide" ones which consist of chars and "wide" ones which consist of wchar_ts and are written as L"" (single wchar_ts can be written as L''). There are functions to convert between them; apart from these, you cannot intermix them.
Depending on the system, a wchar_t can be 16 or 32 bits wide.
You should view your string as an array of characters (in this case, 8-bit characters) so a uint8_t would suffice. What you normally do is pass the beginning of the string (which is the pointer to the array) to your function. To make it safer, you could also pass the length of the string as an argument, but normally your string will end with a delimiter (\0).
when you pass stringData to your function, you're actually saying &stringData[0], literally "the address (&) of the first element ([0]) of the array".
i know its old problem , but what will be the easy solution to keep the old logic of c app (legacy) that now converted to c++ ?
in c its working :
void *p;
void *response = malloc(60 * 81);
p = response ;
p+=4;
in g++ gives : ISO C++ forbids incrementing a pointer of type ‘void*’
update:
if i change it to char* im getting this error:
char *p;
char *response = malloc(60 * 81);
error: invalid conversion from ‘void*’ to ‘char*’
also does char* can hold other types (basic ones ) like short , int , bool ?
this is why it is used in this legacy code , to hold diffident types ,
The simplest would be to cast the void * to char *. Since ISO C also forbids void* arithmetic, gcc treats it as a char* as an extension. See this for more details: http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Pointer-Arith.html#Pointer-Arith
It's only working in gcc. Pointer arthimetic on void * is undefined. Gcc treats it like a char * in that case. So the best way to fix your legacy code is to carefully change all those pointers to char *.
The easiest might be to look for compiler options to change this behavior.
The best is probably to change the type to char *, since that seems to match usage and intent.
Porting from gnu C to C++ is non trivial. Arithmetic on void* is not C, it is an extension.
Porting such things to C++ should be done more carefully, in particular if the C code was not too proper from the start. That data has an "intended" type, so you should use that type in C++ and not yet another second guess like char. Obviously this was not thought to be a C string, doing += 4 for C strings makes not much sense. So there is the assumption that the base type has a size of 4, probably from the rest of the code you can guess how this has to be interpreted.
Once you have the proper type, use new[] to allocate the array. Don't use malloc in C++ if you can avoid it.
Because of "arithmetic of pointeur" ...
if you write p += 4 it means : p += ((sizeof(void *) * 4)
I have a C code in long file that is compiled using cc. But when I tried to compile on gcc it gives error. I took that particular code in small program and try to compile on cc but it failed over there.
Here is source:
#include <stdio.h>
int main (int argc, char **argv)
{
char unsigned FileName[100];
char test[100];
FileName[strstr(FileName,test) - FileName] = 0;
return 0;
}
This line is causing the problem:
FileName[strstr(FileName,test) - FileName] = 0;
error on CC is :
"foo.c", line 10: operands have incompatible types:
int "-" pointer to unsigned char
and on gcc is :
foo.c:10: error: invalid operands to binary - Both are same.
But when I compile original file on CC it compiled and just give a warning. Like this:
"dbtprc.c", line 643: warning: argument #1 is incompatible with prototype:
prototype: pointer to const char : "/usr/include/iso/string_iso.h", line 133
argument : pointer to unsigned char
"dbtprc.c", line 643: warning: improper pointer subtraction
Can you please help why here it is giving warning "improper pointer subtraction" and sample program it is showing error?
Don't you missed to include <string.h> ??
If yes, the prototype of strsrt is guessed and by default it returns an int, hence the invalid pointer operation.
Otherwise, it appears that the signedness mismatch is the cause of the warning/error.
Use a (char*)cast before the two occurence of your table and it will go.
Is there anything called Array Arithmetic in C? Read this:
Arrays are not Pointers.
And see how to use strstr().
void * bar;
void * foo;
...
foo = bar + 1;
That's undefined behaviour, right there! You are referring to a memory location that wasn't even allocated.
EDIT:
Now you have another problem: even though you sucessfully declared both arrays, you failed to clean/initialize them. Only god knows what strstr() will return to you.
The problem you have compiling this code is that strstr() takes 2 const char* and you defined Filename as unsigned: char unsigned FileName[100];
char *strstr(const char *haystack, const char *needle);
An error or a warning is not much different, just showing how serious the compiler believes the issue is.
But why do you use unsigned char for the filename? That's in conflict with strstr which only handles char*, both for its parameter and return type.
That's what the compilers try to tell you, in different ways.