I'd have a quick question over my codes:
int main(void)
{
int i,j,key[5][5],ikey[5][5],row,col,plen,suc;
int devide,count,h,k,no,p1[100],e1[100],d1[100];
char p[100],e[100],d[100],clen;
printf("Enter your plaintext::::::::");
gets(p);
plen = strlen(p); // this line gets error
warning line is:
plen = strlen(p);
implicit conversion loses integer precision unsigned long to int.
As already mentioned the function strlen(p) returns a value of type size_t. Here is an abstract from the C99 standard:
size_t
which is the unsigned integer type
Now the point here is that what exact type it is(unsigned, unsigned long etc.) is actually implementation-defined, which means it varies depending on the platform. Obviously you have it defined as unsigned long which means that by
plen = strlen(p);
you convert unsigned long to int which the compiler can't ignore because in some cases this conversion may lose the value's precision.
The correct declaration:
#include <stddef.h>
size_t plen;
// ...
plen = strlen(p);
As others have already pointed out, strlen() returns a size_t.
Related
void main() {
unsigned int a = 0;
if (a - 10 < 0) {
printf("error!\n");
}
}
we know this comparison won't work, because a-10 will be a big unsigned integer, it can't be smaller than 0.
To avoid this situation, I try this:
void main() {
unsigned int a = 0;
int b = 0;// or const int b = 0;
if (a - 10 < b) {
printf("error!\n");
}
}
this will get warning C4018 using Visual Studio 2022 17.2.4.
However, when I use gcc 4.8.5, there is no warning at all.
Is there a way to avoid coder compare signed number with unsigned variable?
Update:
a more complex situation could be this:
struct s{
unsigned int len;
char *buffer;
} *a;
int not_safe(struct s *ptr){
if(ptr->len - sizeof(struct s) < 0){
return 0;
}
return 1;
}
Programmers may not be aware of such comparisons are wrong. I
hope we can have a safe way to let programmer avoid this.
If you cast the unsigned int operand to int:
if ((int)a - 10 < 0)
Then all of the math with be done using type int.
Or, you can do a little bit of algebra:
if (a < 10)
To avoid the problem completely.
Please study what C formally calls the usual arithmetic conversions Implicit type promotion rules. The TL;DR is that in case you have two integers of the same size but different signedness, the signed one will get converted to unsigned.
You could explicitly cast the unsigned operand to signed. Or you could let the signed operand be a larger type than the unsigned, such as int64_t, in which case the unsigned int (likely 16 or 32 bits) will get converted to int64_t.
But that won't solve your root problem which is this line:
if(ptr->len - sizeof(struct s) < 0)
This is doesn't make any sense to begin with. And casting ptr->len to int64_t might not help either size sizeof returns a size_t, which is guaranteed to be a large unsigned integer type. Simply replace this with:
if(sizeof(struct s) > ptr->len)
Or if you will, change the whole function to one following common best practices:
bool not_safe (const struct s* ptr) {
return sizeof(struct s) > ptr->len;
}
Foreword: I am not allowed to use any functions from the C library
I have this function:
char *to_base(long nbr, char *base)
{
static char buffer[50];
char *ptr;
int base_len;
ptr = &buffer[49];
*ptr = 0;
base_len = ft_strlen(base);
while (nbr != 0)
{
*--ptr = base[nbr % base_len];
nbr /= base_len;
}
return (ptr);
}
As we can see it takes a long. In my program I have an unsigned long which I have to translate into its hexadecimal value. Is it unsafe to pass the unsigned long at this function ? If yes how can I make it work ?
EDIT :
Here is how I am currently using it:
unsigned long val;
char *hexa;
val = (unsigned long)va_arg(*list, void *);
hexa = to_base(val, "0123456789abcdef");
Is it unsafe to pass the unsigned long at this function ?
It's "safe", as in the program will not format your hard drive or start another world war.
Passed function arguments are converted to the argument type. The unsigned value will be converted to a signed one. All architectures today use twos-complement, it's easy to predict the result. Your compiler should document the behavior, ex. in gcc implementation defined beahvior:
The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).
For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.
"reduced modulo 2^N" - basically 2^N is subtracted until the value is within range. So if you have 32-bit longs and have (long)(unsigned long)4294967196ul so you subtract 2^32 from the value and it's equal to (long)-100.
If yes how can I make it work ?
Properly handle negative numbers.
And write a separate function for unsigned and signed numbers.
Also (unsigned long)va_arg(*list, void *); is casting a void* pointer value to an unsigned long (?). Most probably you want va_arg(list, unsigned long) - to take unsigned long from arguments.
I'm trying to write a program which starts by creating a 2D array that will represent a graph (note that the dimensions of the graph will be given as input).
I want to initialize this array at 0 and after googling it I found out that you have to do it with memset(), cause the memory for the array will be dynamically allocated from the input file.
Below is a small part of my program so far:
long int N;
int main(int argc, char *argv[]) {
long int i;
FILE * txt;
txt = fopen(argv[1], "r");
if (txt == NULL) {
printf("There was an error trying to open the file.\n");
return 0;
}
fscanf(txt, "%li", &N);
long int graph[N][N];
memset(graph, 0, N*N*sizeof(long int));
return 1;
}
When I'm compiling it with gcc -Wconversion i'm getting the following warning:
warning: conversion to ‘long unsigned int’ from ‘long int’ may change
the sign of the result [-Wsign-conversion] memset(graph, 0,
N*N *sizeof(long int));
I can't understand at which point of the code the compiler is trying to convert a long int to an unsigned one. I searched it and people had the same problem only when they had variables of different types mixed.
Any help would be appreciated!
---EDIT---
With the help of 'Vlad from Moscow' I was able to solve the above warning (I had to change N to size_t type in order to call memset() correctly), but now I want to initialize another long int array to LONG_MAX and I get a different one:
memset(dist, LONG_MAX, N*sizeof(long int));
warning: overflow in implicit constant conversion [-Woverflow]
The function memset expects the third argument of the type size_t.
So declare the variable N as
size_t N;
and write
fscanf(txt, "%zu", &N);
The second warning is related to the second argument of the call of memset
memset(dist, LONG_MAX, N*sizeof(long int));
that expects it of the type int that is internally within the function is converted to the type unsigned char.
Here is the function declaration.
void *memset(void *s, int c, size_t n);
Usually the only applying of the function is to zero-initialize an array.
size_t may interpreted as unsigned int or as unsigned long int; depends on machine.
There is no need to use memset() for fill the array with 0s, you can give this stuff to compiler.
Simply assign 0 to first element and compiler will assign 0 to all uninitialized elements!
long int graph[N][N] = {0};
You are trying to use memset() in wrong place!
memset() sets the storage in 'bytewise manner'.
void *memset(s,c,n) --> place character c into first n characters of
s, return s
notice that c is a character not an integer.
So, how to initialize an array with LONG_MAX ?
Using a loop:
for(long i = 0; i < N; ++i)
dist[i] = LONG_MAX;
I have a program that uses unsigned chars to represent integers with a small range. I find myself needing to clear them to 0 in several different parts of the program, I have also recently started using splint and apparently:
unsigned char c = 0;
gives the warning:
Variable c initialized to type int, expects unsigned char: 0
Types are incompatible.
As there is no suffix for a literal char, How is it best to resolve this? I think I have a few options:
1: Ignore the warning.
2: Cast every time:
unsigned char c = (unsigned char)0;
3: Make a var to cut down the length of the code:
unsigned char uc_0 = (unsigned char)0;
unsigned char c = uc_0;
4: A function:
static inline unsigned char uchar(int in)
{
return (unsigned char)in;
}
unsigned char c = uchar(0);
splint has an option +charint that will treat char int as interchangeable.
You can ignore the warnings and use
unsigned char = 0;
In many cases when there is integer operation in order to save memory instead of using int which obviously consumes extra memory than char people do make use of unsigned char.
unsigned char i = 10;
unsigned char j = 1;
unsigned char k = i +j;
printf("%d",k);
I've just a great programming puzzle. Why is to same?
#include <stdio.h>
#include <limits.h>
int main(int argc, char *argv[])
{
unsigned int x = ULONG_MAX;
char y = -1;
if (x == y) printf("That is same.");
return 0;
}
I think that unsigned int is converted to signed char, and thus it will be -1. It may be a standard for comparison of signed and unsigned type. I don't know...
In a tiff between signed char and unsigned int, unsigned int wins!
Its like this
Here -1 will be converted to unsigned int which is ULONG_MAX and hence if() condition is true.
In C, size does matter. Variables are always converted to the highest size among them.
Many years ago, I learned a couple of things. One of them was compare like types.
I would either cast the char to an unsigned int if the unsigned int's value is greater than sizeof char. Or cast the other way if the unsigned int's values are to be restricted to a sizeof char. In that way, you are telling the compiler how you are comparing the values, and it will help maintainers as well.