I am developing a program to read 2 strings (addresses) entered by the user and then apply the operator &
and thus obtain a new address.
For example, if the user enters 172.217.0.164
and then 255.255.0.0
, the result of applying the operator &
between the two addresses would be 172.217.0.0
. Which is what I intend to obtain when performing the operation in C
.
The problem is that I get the following error:
[Error] invalid operands to binary & (have 'char *' and 'char *')
- The code in
C
:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *direccion;
char *mascara;
direccion = (char *)calloc(16, sizeof(char));
mascara = (char *)calloc(16, sizeof(char));
printf("Introduce la primera direccion ip: ");
scanf("%s", direccion);
printf("Introduce la mascara de dicha direccion: ");
scanf("%s", mascara);
/*aplicar bit a bit con el operador &*/
char *n;
n = direccion & mascara;
printf("La nueva direccion es la siguiente %s", n);
return 0;
}
There are several misconceptions in your approach:
You can't do
&
between pointersThe operation
&
performs a logical AND between the bits of the data you pass to it. For example, if you pass as data (to the left and to the right of the operator&
) the numbers 7 and 12, which in binary are00000111
and00001100
respectively, then the result will be00000100
, that is, 4, since the operation has been carried out:The result only has 1 where both data have 1.
In your code you do
direccion & mascara
, butdireccion
andmascara
are pointers. A pointer is a number that represents a memory address (in this case the address where the strings are). If the compiler had allowed you to use this instruction, the result would be another binary number that would be the AND between the bits of both pointers. This doesn't make sense, and the compiler won't let you do it.The correct approach would be to loop through the bytes pointed to by
direccion
and at the same timemascara
to do an AND for each of them, and store the result in addresses pointed to byn
. Something like the following:Now run this and you will get the following surprise:
What happened?
You are doing
&
between the ASCII codesIndeed, the data it points to
direccion
is the character'1'
(the first character of the string entered by the user), and the data it points tomascara
is the character'2'
. When you do the operation&
between them, you will not be doing it between 1 and 2, but between the ASCII code of '1' and the ASCII code of '2', because that is what strings store.The ASCII code for '1' is 00110001 (49) and for '2' is 00110010 (50). If you do the AND bit by bit between those amounts you get
00110000
(48). And it turns out that's the ASCII code for zero! That's why the result has a 0 as the first character.And so you can see all the others. Curious note, the point is respected because the groups of numbers have the same length in the address and in the mask, so there comes a time when you have to do the
&
between the ASCII code of one'.'
and the ASCII code of another'.'
, which obviously returns the ASCII code of another'.'
However, this is not what was sought. It's all wrong because...
An IP is not a string
But it is that even if the ASCII codes were not involved, it would still be wrong, because an IP address is actually a 32-bit data , and when you write it in the form
"172.217.0.164"
, that is nothing more than a trick to make it easier for us to remember or type.In that string you are actually representing four bytes . The IP is actually a 32-bit binary number that comes out of concatenating the binary representation of each of those 4 bytes. In this case it would be:
That is, the IP is the number
10101100110110010000000010100100
that in decimal would be 2899902628. That is the IP and the dot notation is just an easier way to write it.Only having the IPs as 32-bit binary numbers does it make sense to do
&
between that number and the mask (which by the way would be11111111111111110000000000000000
). The representation as a dot-separated string does not work for us.how to do it right
You need to convert the user-entered string (using dot notation) to a 32-bit number, both for the address and the mask. That conversion is not trivial. You have to detect where the dots are, separate by them, convert each resulting substring to an 8-bit integer, and then concatenate those four integers to form a single larger 32-bit integer. Only then will you have the IP in a suitable format to be able to apply the operation to it
&
.Luckily the C standard library has functions to handle IPs and convert them from their "dot-separated string" form to their internal representation as a 32-bit binary number, and vice versa (to print the result we need to convert it back from its internal representation 32-bit binary to a string that has the values of each byte separated by dots).
If you're not familiar with the sockets API, the code can be a bit confusing, but here's how you could do it:
And now it works fine:
The error is clear and concise, perhaps you do not understand it because it is in English, I will translate it for you:
It is clearly telling you that the binary & operator cannot be used on operands that are pointers to character (
char *
). And this is how it is established in the C standard (my translation):Pointers are not integral types, but ( counterintuitive as it may seem ) points
char
are. So you can apply the mask character by character:But this is not what you want:
That is doing the binary and on the characters of the numbers, not on the numbers. It makes about as much sense as battering a photo of a chicken thigh.
Character
'1'
has value 49 and character'2'
has value 50:Therefore:
The same operation with the rest of the chain:
I am using underscore (
_
) as null characterIt's clear that you don't really want to work with character strings but with 8-bit integer values.
Proposal.
Read all four components of the IP address, not the IP as a string, don't use dynamic memory unnecessarily, and initialize your variables: