LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-15-2014, 01:53 PM   #1
kikilinux
Member
 
Registered: Sep 2012
Posts: 125

Rep: Reputation: Disabled
Question The best way to perform bitwise operation on hexadecimal value ?


Hi
The problem is :i have a hex value just like bellow:
unsigned char * temp = "\x4b001cdb3349"

ok now i want to set specific bit of this string (change that bit to 1) in C.
I know many ways are exist to do that but maybe the way i choose has unnecessary overhead.
I can read the first byte (4b) convert to decimal value and do OR with the value that its bits is set to 1 (this could be a one solution).

but any other suggestion ?
 
Old 05-15-2014, 02:19 PM   #2
suicidaleggroll
LQ Guru
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 5,573

Rep: Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142
That's not a hex value, it's a string. Are you trying to set a bit in the string, or are you trying to read two characters in the string as a single hex byte, set a bit in that, and then convert back to a pair of characters and insert it back into the string?

For example, take the string "4a"

If you interpret the characters in this string as two hex values, you get the decimal number 74, and the binary number 01001010. If you want to set the fifth bit, you would get 01011010, or decimal number 90, or hex number 5a. Then you could convert this back to the string "5a".

On the other hand, if you set the fifth bit in your string, you get a very different answer. The ASCII characters "4a" are the hex numbers 34 and 61 respectively (52 and 97 in decimal). This converts to the binary numbers 00110100 and 01100001. If you set the fifth bit here, you get 00110100 and 01110001, 34 and 71 in hex, 52 and 113 in decimal, which maps back to the ASCII characters "4q".

Last edited by suicidaleggroll; 05-15-2014 at 02:31 PM.
 
2 members found this post helpful.
Old 05-15-2014, 03:29 PM   #3
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,659
Blog Entries: 4

Rep: Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941
Okay, with a little finagling you should be able to sccanf() that string-value using an appropriate format-string to get your binary number. (A longint, looks like.) Then, you can perform the bitwise operations against that.

First, convert the value and store it in a longint variable. Trap any exceptions that occur, and deal with them appropriately.) Then, mash the bits.
 
Old 05-15-2014, 03:52 PM   #4
metaschima
Senior Member
 
Registered: Dec 2013
Distribution: Slackware
Posts: 1,982

Rep: Reputation: 492Reputation: 492Reputation: 492Reputation: 492Reputation: 492
You need to be more specific about the problem you have. Provide working code and then we will see. To change one bit of a certain variable you can use a mask and the | (logical or) operator. This is the usual way to do it, but your code doesn't make sense.

Code:
bash-4.2$ cat str.c 
#include <stdio.h>

int main (void)
{
	 unsigned char * temp = "\x4b001cdb3349";

	 printf ("%s\n", temp);

	return 0;
}
bash-4.2$ compile str.c 
str.c: In function 'main':
str.c:5:26: warning: hex escape sequence out of range [enabled by default]
   unsigned char * temp = "\x4b001cdb3349";
                          ^
str.c:5:26: warning: pointer targets in initialization differ in signedness [-Wpointer-sign]
bash-4.2$ ./str 
I
If you had an actual string, you would have to convert it using scanf() or atoi().
 
Old 05-15-2014, 07:20 PM   #5
jailbait
LQ Guru
 
Registered: Feb 2003
Location: Virginia, USA
Distribution: Debian 12
Posts: 8,337

Rep: Reputation: 548Reputation: 548Reputation: 548Reputation: 548Reputation: 548Reputation: 548
Quote:
Originally Posted by kikilinux View Post

I can read the first byte (4b) convert to decimal value and do OR with the value that its bits is set to 1 (this could be a one solution).

but any other suggestion ?
Do the bit twiddling in hex, not decimal. You can do anything you want to a bit with AND, OR, and XOR and using the appropriate mask.

-----------
Steve Stites
 
1 members found this post helpful.
Old 05-15-2014, 11:46 PM   #6
kikilinux
Member
 
Registered: Sep 2012
Posts: 125

Original Poster
Rep: Reputation: Disabled
Ok
I have this code:


unsigned char * h1;
unsigned char * h2;
h1 = malloc(sizeof(char));
h2 = malloc(sizeof(char));
*h1 = '\x08';
*h2 = '\x04';

printf("the result is : %x\n", *h1 | *h2);

And it works.
Actually i am working on IP packet header.
I need to set a specific bit inside IP packet header in kernel using netfilter loadable kernel module.
I have access to IP header and i want to set some bits to 1 in the header.
For example i want to read specific byte from IP option field and set some bits to 1.
I have tested it by copying IP header to an unsigned char * variable and perform bitwise operation on it and it worked.
but now i want to perform the operation on ip packet header directly.

the code for bitwise operation is as bellow :

unsinged char * temp;
unsigned char * insertByte;

// some code

temp = kmalloc(ip_header->ihl * 4, GFP_KERNEL);
memcpy(temp, ip_header , ip_header->ihl * 4);
insertByte = kmalloc(sizeof(char), GFP_KERNEL);
insertByte = "\x01";
*(temp + 20) = *(temp + 20) | *insertByte;

This code set the first bit of Twentieth-first byte to 1 in temp variable but i want to perform this operation on same byte of the IP header directly.

any suggestion would be greatly appreciated.
 
Old 05-16-2014, 02:41 AM   #7
Syndacate
Member
 
Registered: Aug 2008
Location: Santa Clara, CA
Distribution: Ubuntu, mainly. Too much stuff works out of the box O.o
Posts: 71

Rep: Reputation: 52
Quote:
Originally Posted by kikilinux
unsinged char * temp;
unsigned char * insertByte;

// some code

temp = kmalloc(ip_header->ihl * 4, GFP_KERNEL);
memcpy(temp, ip_header , ip_header->ihl * 4);
insertByte = kmalloc(sizeof(char), GFP_KERNEL);
insertByte = "\x01";
*(temp + 20) = *(temp + 20) | *insertByte;

This code set the first bit of Twentieth-first byte to 1 in temp variable but i want to perform this operation on same byte of the IP header directly.

any suggestion would be greatly appreciated.
Okay, so maybe I'm not understanding the problem in its entirety (I don't do well w/o pix :-P). Though if you want to set the 21st byte in the IP header to 1 (ie 0000 0001), then you should be able to do it with something like this (untested, but should work):
I'm assuming "ip_header" is local, and not a ptr...if it's a ptr just remove the ampersand.
Code:
char *ip_hdr_ptr = (char*)&ip_header;
*(ip_hdr_ptr + 20) = 1;
No need to copy it into a temp variable, just set it directly in the ip_header.

Maybe I'm misunderstanding something about what you're trying to do (probably the case, lol).

EDIT:
Note that you should use "uint8_t" instead of "char" for stuff like this, as uint8_t is guaranteed to be 8 bits, char is not (ie. unicode). Makes the code a bit more portable. Also note that (especially with IP stuff) that this may not be endian safe.

Last edited by Syndacate; 05-16-2014 at 02:44 AM.
 
2 members found this post helpful.
Old 05-16-2014, 12:43 PM   #8
kikilinux
Member
 
Registered: Sep 2012
Posts: 125

Original Poster
Rep: Reputation: Disabled
Dear Syndacate
thanks to answer, it is not completely same but ur solution is work for me.
I want the to set a specific bit of specific byte for example "first bit of 21st byte".
i problem solved.

Best
 
Old 05-16-2014, 01:10 PM   #9
kikilinux
Member
 
Registered: Sep 2012
Posts: 125

Original Poster
Rep: Reputation: Disabled
Lets i illustrate what i want to do.
For example, this is the ip header : "00 4c .... 0a 04 00 00"
Lets assume the last fourth bytes are 21st to 24st bytes of ip header.
Then i want to set second bit of 22st byte to 1.

struct iphdr *ip_header;

unsigned char * temp;
unsigned char * insertByte;
temp = kmalloc(ip_header->ihl * 4, GFP_ATOMIC);
insertByte = kmalloc(sizeof(char), GFP_ATOMIC);
temp = (unsigned char *)ip_header; // Adjust temp to point to ip header
insertByte = "\x02";
*(temp + 22) = *(temp + 22) | *insertByte;

Does my programming accurate ?
Any suggestion to improve the code ?
 
Old 05-16-2014, 01:16 PM   #10
suicidaleggroll
LQ Guru
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 5,573

Rep: Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142Reputation: 2142
I would replace insertByte with just 1<<N, where N is the bit you want to set minus 1

eg:
*(temp+22) = *(temp+22) | (1<<1);

Or if you must use hex, just use hex, I don't understand why you're futzing around with a char * and that weird "\x" notation. I'm pretty sure that's not even a valid escape sequence...

*(temp+22) = *(temp+22) | 0x2;

Or to make it simpler

*(temp+22) |= 0x2;

http://stackoverflow.com/questions/1...es-x-mean-in-c

Last edited by suicidaleggroll; 05-16-2014 at 01:19 PM.
 
1 members found this post helpful.
Old 05-16-2014, 01:35 PM   #11
kikilinux
Member
 
Registered: Sep 2012
Posts: 125

Original Poster
Rep: Reputation: Disabled
woooow
I don't know programming at all.
Thanks to answer.
I have to work a lot on my programing skill.

Best
 
Old 05-16-2014, 02:38 PM   #12
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Code:
temp = kmalloc(ip_header->ihl * 4, GFP_ATOMIC);
...
temp = (unsigned char *)ip_header; // Adjust temp to point to ip header
This is a memory leak, you're throwing away the value returned from kmalloc().

Quote:
Originally Posted by suicidaleggroll View Post
where N is the bit you want to set minus 1
Or just number the bits from 0, like God intended.
 
Old 05-16-2014, 03:20 PM   #13
kikilinux
Member
 
Registered: Sep 2012
Posts: 125

Original Poster
Rep: Reputation: Disabled
Lets i fixed the errors;
1 - i don't need to allocate any memory to temp variable and at the end of program kfree(insertByte)
or
2 - just kfree temp and insertByte

do i am correct ?
 
Old 05-16-2014, 04:55 PM   #14
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by kikilinux View Post
1 - i don't need to allocate any memory to temp variable and at the end of program kfree(insertByte)
If you follow suicidaleggroll's advice you don't need to allocate insertByte either.

Quote:
or
2 - just kfree temp and insertByte
You can't kfree temp once you have overwritten the original value that came from kmalloc.
 
Old 05-16-2014, 05:03 PM   #15
Chickentree
LQ Newbie
 
Registered: Feb 2012
Posts: 5

Rep: Reputation: Disabled
Would it not be better to use a standard header with the defines available there?
On my Debian system that would appear to be /usr/include/netinet/ip.h. That header seems to define the available fields and flags and would make the purpose of your code much clearer.
 
  


Reply

Tags
bits, programming



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Can we perform TWO MMAP operation on same /dev file dgashu Programming 3 01-31-2013 09:48 AM
C program to perform an operation continuously until user presses a key ananth86coolguy Linux - Newbie 4 03-13-2009 09:59 AM
how do i use bash to perform an operation on multiple files Brynn Linux - Newbie 6 07-24-2006 06:02 AM
Perform an operation on files x, y...direct output to x.out, y.out respectively johndoe0028 Linux - General 6 04-02-2006 10:39 PM
about bitwise operators? eshwar_ind Programming 17 10-25-2004 02:13 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:30 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration