Pointers in C and casting - c

I've started learning pointers this time. Im trying to read bytes from this array. Task is almost done but CLang keep warns me with warning I don't understand. Here's my code.
Warning says : " Function call argument is an uninitialized value"
int main(void)
{
int tab[] = {67305985,134678021,202050057};
int *pp=0;
pp=tab;
char *wsk=(char*)pp;
for (int i = 0; i < 12; i++)
{
if((wsk+i)!=(void*)NULL)
printf("%d ",*(wsk+i)); // warning on this line
else
return 0;
}
}

These warnings are from Clang Static Analyzer (or whatever they call it these days).
It looks like a false positive to me, if we assume that int is at least 4 bytes and the real code has #include <stdio.h> and no other changes.
If you're using the latest version of the analyzer, you could file a clang bug report. Well -- you could if they allowed people who don't already have accounts to file bug reports. Maybe someone else reading this thread can do it.
Note: it would help the question to post exactly which version of the analyzer you are running (this may be different to the compiler you're using to build -- some IDEs use different compilers for building than for these inline messages).

This if statement
if((wsk+i)!=(void*)NULL)
does not make sense. The macro NULL is already a null pointer constant. So there is no sense to cast it to void *.
And the pointer wsk+i can not be equal to NULL in this loop because initially it points to an object.
Just remove the if statement and output each character in the loop.
And it is a bad idea to use magic numbers like 12 used in the loop.
You could write for example
const size_t N = sizeof( tab ) / sizeof( *tab );
and then in the loop
for ( size_t i = 0; i < N * sizeof( int ); i++ )
//...
As for the warning then it is irrelative to the presented code provided that you included the header <stdio.h>.

wsk will never be null, since you've set it to be the same as tab (arrays, in C/C++ are just pointers to a block of data. The warning is telling you that no matter how much you add to wsk it will always be non-null. What you need to do is limit your iterations in the loop to the number of valid items in the array, since C/C++ arrays have no terminators of any kind.
The printf might just be confusing CLang. Try printf("%d ", wsk[i]);

Related

How do I use tolower() with a char array?

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.

How does this implementation of randomization work in C?

Since I found this particular documentation on https://www.tutorialspoint.com/c_standard_library/c_function_rand.htm,I have been thinking about this particular line of code srand((unsigned)time(&t));.Whenever I had to generate some stuff,I used srand(time(NULL)) in order not to generate the same stuff everytime I run the program,but when I came across this,I have been wondering :Is there any difference between srand((unsigned)time(&t)) and srand(time(NULL))?Because to me they seem like they do the same thing.Why is a time_t variable used?And why is the adress operator used in srand()?
#include <stdio.h>
#include<stdlib.h>
int main(){
int i,n;
time_t t;
n = 5;
srand((unsigned)time(&t));
for (i = 0; i < n; i++) {
printf("%d\n", rand() % 50);
}
return(0);
}
Yes, it will yield the same result. But the example is badly written.
I would be careful reading Tutorialspoint. It's a site known for bad C code, and many bad habits you see in questions here at SO can be traced to that site. Ok, it's anecdotal evidence, but I did ask a user here why they cast the result of malloc, and they responded that they had learned that on Tutorialspoint. You can actually see (at least) four examples in this short snippet.
They cast the result from the call to time() which is completely unnecessary and just clutters the code.
For some reason they use the variable t, which is completely useless in this example. If you read the documentation for time() you'll see that just passing NULL is perfectly adequate in this example.
Why use the variable n? For this short example it's perfectly ok with a hardcoded value. And when you use variables to avoid hardcoded values, you should declare them const and give them a much more descriptive name than n. (Ok, I realize I was a bit on the edge when writing this. Omitting const isn't that big of a deal, even if it's preferable. And "n" is a common name meaning "number of iterations". And using a variable instead of a hard coded value is in general a good thing. )
Omitted #include<time.h> which would be ok if they also omitted the rest of the includes.
Using int main() instead of int main(void).
For 5, I'd say that in most cases, this does not matter for the main function, but declaring other functions as for example int foo() with empty parenthesis instead of int foo(void) could cause problems, because they mean different things. From the C standard:
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
Here is a question related to that: What are the semantics of function pointers with empty parentheses in each C standard?
One could also argue about a few other things, but some people would disagree about these.
Why declare i outside the for loop? Declaring it inside have been legal since C99, which is 20 years old.
Why end the function with return 0? Omitting this is also ok since C99. You only need to have a return in main if you want to return something else than 0. Personally, in general I find "it's good practice" as a complete nonsense statement unless there are some good arguments to why it should be good practice.
These are good to remember if your goal is to maintain very old C code in environments where you don't have compilers that supports C99. But how common is that?
So if I got to rewrite the example at tutorialspoint, i'd write it like this:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(void){
srand(time(NULL));
for (int i = 0; i < 5; i++) {
printf("%d\n", rand() % 50);
}
}
Another horrible example can be found here: https://www.tutorialspoint.com/c_standard_library/c_function_gets.htm
The function gets is removed from standard C, because it's very dangerous. Yet, the site does not even mention that.
Also, they teach you to cast the result of malloc https://www.tutorialspoint.com/c_standard_library/c_function_malloc.htm which is completely unnecessary. Read why here: Do I cast the result of malloc?
And although they mention that malloc returns NULL on failure, they don't show in the examples how to properly error check it. Same goes for functions like scanf.

Are arrays with a defined const allowed in C++?

I tried to run the following code with a C++ compiler:
#include <iostream>
#include <string>
using namespace std;
int MAX=10;
int list[MAX];
int main()
{
int sum =0;
for (int i = 0; i<=MAX; ++i){
list[i]=i;
}
for (int i = 0; i<=MAX; ++i){
sum=sum+list[i];
}
cout << sum << endl;
}
But received this error:
"integer array bound is not an integer constant before ‘]’ token"
I don't understand why this is an error because I have defined MAX as 10 right before
int list[MAX]
so shouldn't it work?
Appreciate any help
No compiler error message here, just exactly what the error message says. You haven't included a const before your int MAX declaration.
Capital letters and never changing the value of MAX doesn't mean it's a constant.
Note that some compilers accept having a variable (i.e. int MAX = 10; instead of const int MAX = 10; for array initialization. Don't rely on this because it shouldn't occur.
If you want to use a variable to initialize an array, you need to use pointers:
int size;
cin >> size;
int *list = new int[size];
I don't understand why this is an error because I have defined MAX as 10 right before int list[MAX]
You defined MAX as 10 but you didn't define MAX as constant. It's an error because the compiler insists that (in this case) the array bound must be an integer constant.
One way to fix the error is to make MAX constant...
const int MAX = 10;
int list[MAX];
Another way to avoid the error is to move the array off the stack and onto the heap (since the bound of a heap array doesn't have to be constant) …
auto list = new int[MAX];
… however this changes the type of list from int[10] to int * and also forces you to become responsible for managing the life of list by calling delete when appropriate (which can be a non-trivial challenge) …
delete [] list;
Not deleting list correctly can cause memory leaks.
You can avoid the error and avoid responsibility for managing the array by using a unique_ptr …
std::unique_ptr<int[]> list{ new int[MAX] };
However many well regarded authorities would argue that using a container like std::vector or std::array would be a better approach. For example, in Effective Modern C++ Scott Meyers says this...
The existence of std::unique_ptr for arrays should be of only intellectual interest to you, because std::array, std::vector, and std::string are virtually always better data structure choices than raw arrays. About the only situation I can conceive of when a std::unique_ptr would make sense would be when you’re using a C-like API that returns a raw pointer to a heap array that you assume ownership of.
At this point you may be wondering why MAX has to be constant in your original code. I'm not a language lawyer but I believe the short answer is because the C++ Standard says it must be so.
For insight into why the standard imposes that requirement you could read some of the answers to the question Why aren't variable-length arrays part of the C++ standard?

passing a two-dimmensional array to function

I am trying to compile the following simple code in Workbench:
1. typedef float matrixType[3][3]
2.
3. void my_func(matrixType matrix)
4. {
5. printf("matrix[0][0] = %g\n",matrix[0][0]);
6. }
7.
8. void main()
9. {
10. matrixType my_matrix = {{0,1,2},{3,4,5},{6,7,8}};
11. matrixType* ptr_matrix = &my_matrix;
12.
13. my_func(*ptr_matrix);
14. }
I receive the following warning:
test.c:13: warning: passing arg 1 of `my_func' from incompatible pointer type
I can't understand, what am I doing wrong. The compilation of the same code in Visual Studio works without any warnings, but in Workbench something is going wrong.
Thanks.
With gcc (GCC) 4.5.3 with all warnings turned on it also compiles fine after making the following changes:
Add a semicolon after the first line.
Add #include <stdio.h> at top.
Change the return type of main to int.
Add return 0; as the last line.
The void main() is not correct C even though it appears in various books, manuals, and web tutorials. On some architectures it will cause strange problems, usually as the program terminates.
Taking the address of an array type is challenging the workbench type checker. I'm not going to drag out the C standard to figure out if the workbench warning is correct. It's probably a bug.
But I'm pretty sure that if you recode this way you will see no errors with any compiler:
#include <stdio.h>
typedef float rowType[3];
typedef rowType matrixType[3];
void my_func(matrixType matrix)
{
printf("matrix[0][0] = %g\n",matrix[0][0]);
}
int main()
{
matrixType my_matrix = {{0,1,2},{3,4,5},{6,7,8}};
rowType* ptr_matrix = my_matrix;
my_func(ptr_matrix);
return 0;
}
The reason is that my_matrix is automatically converted to a pointer to it's first element in the assignment
rowType* ptr_matrix = my_matrix;
This is just as in
char s[] = "hello world!";
char *p = s;
the array name s is converted to a pointer to its first element.
The parameter in void my_func(matrixType matrix) has a type identical to rowType* because all arrays are also passed as pointers to first elements. So all the types in this code must match in a way that's very clearly defined in the C standard. &my_matrix may not be incorrect, but it's an "edge case" more likely to expose type checking bugs.
You are missing a semicolon at the end of line 1.

C Compile-Time assert with constant array

I have a very big constant array that is initialized at compile time.
typedef enum {
VALUE_A, VALUE_B,...,VALUE_GGF
} VALUES;
const int arr[VALUE_GGF+1] = { VALUE_A, VALUE_B, ... ,VALUE_GGF};
I want to verify that the array is initialized properly, something like:
if (arr[VALUE_GGF] != VALUE_GGF) {
printf("Error occurred. arr[VALUE_GGF]=%d\n", arr[VALUE_GGF]);
exit(1);
}
My problem is that I want to verify this at compile time. I've read about compile-time assert in C in this thread: C Compiler asserts. However, the solution offered there suggests to define an array using a negative value as size for a compilation error:
#define CASSERT(predicate, file) _impl_CASSERT_LINE(predicate,__LINE__,file)
#define _impl_PASTE(a,b) a##b
#define _impl_CASSERT_LINE(predicate, line, file) \
typedef char _impl_PASTE(assertion_failed_##file##_,line)[2*!!(predicate)-1];
and use:
CASSERT(sizeof(struct foo) == 76, demo_c);
The solution offered dosn't work for me as I need to verify my constant array values and C doesn't allow to init an array using constant array values:
int main() {
const int i = 8;
int b[i]; //OK in C++
int b[arr[0]]; //C2057 Error in VS2005
Is there any way around it? Some other compile-time asserts?
In the code below, see the extra assignement to pointers declared with fixed length in lines 6 and 9.
This will give errors on compile time if the 2 arrays are not initialized for all values of the WORKDAYS enum. Gcc says: test.c:6:67: warning: initialization from incompatible pointer type [enabled by default]
Imagine some manager adding SATURDAY to the work week enum. Without the extra checks the program will compile, but it will crash with segmentation violation when run.
The downside of this approach is that it takes up some extra memory (I have not tested if this is optimized away by the compiler).
It is also a little hackish and probably some comments are required in the code for the next guy...
Please observe that the arrays that are tested should not declare the array size. Setting the array size will ensure that you have reserved the data, but not ensure that it contains something valid.
#include <stdio.h>
typedef enum { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, NOF_WORKDAYS_IN_WEEK } WORKDAYS;
const char * const workday_names[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };
const char * const (*p_workday_name_test)[NOF_WORKDAYS_IN_WEEK] = &workday_names;
const int workday_efforts[] = { 12, 23, 40, 20, 5 };
const int (*p_workday_effort_test)[NOF_WORKDAYS_IN_WEEK] = &workday_efforts;
main ()
{
WORKDAYS i;
int total_effort = 0;
printf("Always give 100 %% at work!\n");
for(i = MONDAY; i < NOF_WORKDAYS_IN_WEEK; i++)
{
printf(" - %d %% %s\n",workday_efforts[i], workday_names[i]);
total_effort += workday_efforts[i];
}
printf(" %d %% in total !\n", total_effort);
}
By the way, the output of the program is:
Always give 100 % at work!
- 12 % Monday
- 23 % Tuesday
- 40 % Wednesday
- 20 % Thursday
- 5 % Friday
100 % in total !
The problem is that in C++ a compile-time constant expression has the following limitations (5.19 Constant expressions):
An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.
Remember that an array indexing expression is really just pointer arithmetic in disguise (arr[0] is really arr + 0), and pointers can't be used in constant expressions, even if they're pointers to const data. So I think you're out of luck with a compile time assertion for checking array contents.
C is even more limited than C++ in where these kinds of expressions can be used at compile time.
But given C++'s complexity, maybe someone can come up with a think-outside-the-box solution.
You can express your assertion as a property to check with a static analyzer and let the analyzer do the check. This has some of the properties of what you want to do:
the property is written in the source code,
it doesn't pollute the generated binary code.
However, it is different from a compile-time assertion because it needs a separate tool to be run on the program for checking. And perhaps it's a sanity check on the compiler you were trying to do, in which case this doesn't help because the static analyzer doesn't check what the compiler does, only what it should do.
ADDED: if it's for QA, then writing "formal" assertions that can be verified statically is all the rage nowadays. The approach below is very similar to .NET contracts that you may have heard about, but it is for C.
You may not think much of static analyzers, but it is loops and function calls that cause them to become imprecise. It's easier for them to get a clear picture of what is going on at initialization time, before any of these have happened.
Some analyzers advertise themselves as "correct", that is, they do not remain silent if the property you write is outside of their capabilities. In this case they complain that they can't prove it. If this happens, after you have convinced yourself that the problem is with the analyzer and not with your array, you'll be left where you are now, looking for another way.
Taking the example of the analyzer I am familiar with:
const int t[3] = {1, 2, 3};
int x;
int main(){
//# assert t[2] == 3 ;
/* more code doing stuff */
}
Run the analyzer:
$ frama-c -val t.i
...
t.i:7: Warning: Assertion got status valid.
Values of globals at initialization
t[0] ∈ {1; }
[1] ∈ {2; }
[2] ∈ {3; }
x ∈ {0; }
...
In the logs of the analyzer, you get:
its version of what it thinks the initial values of globals are,
and its interpretation of the assertion you wrote in the //# comment. Here it goes through the assertion a single time and finds it valid.
People who use this kind of tool build scripts to extract the information they're interested in from the logs automatically.
However, as a negative note, I have to point out that if you are afraid a test could eventually be forgotten, you should also worry about the mandatory static analyzer pass being forgotten after code modifications.
No. Compile-time assertion doesn't work in your case at all, because the array "arr[ARR_SIZE]" won't exist until the linking phase.
EDIT: but sizeof() seems different so at least you could do as the below:
typedef enum {VALUE_A, VALUE_B,...,VALUE_GGF} VALUES;
const int arr[] = { VALUE_A, VALUE_B, ... ,VALUE_GGF};
#define MY_ASSERT(expr) {char uname[(expr)?1:-1];uname[0]=0;}
...
// If initialized count of elements is/are not correct,
// the compiler will complain on the below line
MY_ASSERT(sizeof(arr) == sizeof(int) * ARR_SIZE)
I had tested the code on my FC8 x86 system and it works.
EDIT: noted that #sbi figured "int arr[]" case out already. thanks
As I'm using a batch file to compile and pack my application, I think that the easiset solution would be to compile another simple program that will run through all of my array and verify the content is correct.
I can run the test program through the batch file and stop compilation of the rest of the program if the test run fails.
I can't imagine why you'd feel the need to verify this at compile time, but there is one wierd/verbose hack that could be used:
typedef enum {
VALUE_A, VALUE_B,...,VALUE_GGF
} VALUES;
struct {
static const VALUES elem0 = VALUE_A;
static const VALUES elem1 = VALUE_B;
static const VALUES elem2 = VALUE_C;
...
static const VALUES elem4920 = VALUE_GGF;
const int operator[](int offset) {return *(&elem0+offset);}
} arr;
void func() {
static_assert(arr.elem0 == VALUE_A, "arr has been corrupted!");
static_assert(arr.elem4920 == VALUE_GFF, "arr has been corrupted!");
}
All of this works at compile time. Very hackish and bad form though.

Resources