Sometime you may lose your mind on how to operate with single bit in an integer, moreover if you are not using bit operation for a long time. This is a quick refresh to deal with single bit operation.
Given variable a type of int
To set the nth bit
a |= (1 << n)
To clear the nth bit
a &= ~(1 << n)
To toggle the nth bit
a ^= (1 << n)
To get nth bit value
a >> n & 1
Showing posts with label C. Show all posts
Showing posts with label C. Show all posts
Friday, February 10, 2012
Friday, October 14, 2011
Learn To Code
Programming in C by Stephen G. Kochan (Sams Publishing, 2005) is my first C textual book that I ever had in the time. I download the PDF version and print it as a book 5 years ago. I read and learned almost each page of that book, solve each chapter's exercises with gcc or pseudo-code (if not at my computer), I can say I slept with the book in every single day, that's the very curious thing that I did for learning a computer programming language. I also have (the famous) The C Programming Language by the creator Dennis Ritchie and co-writer Brian Kernighan (Prantice Hall, 1978), Practical C Programming (O'Relly), but I waste a lot of my time with Kochan's book.
With those books, I had impressive proggress in C programming, I extend that improvement by learning real world's implementation such as Linux system and kernel programming upto GUI toolkit programming, then I start to write some simple program just for hobby. The hobby wouldn't keep me only for this, I also write a few of larger program to be released as free software. Surprisingly, they got some intentions and appreciation by the public.
And here I am, 5 years from the time I was learning. I don't know where I supposed to be if I didn't grab that book then start to write code in that time, I already wrote many simple upto big complex program using C. And what I got now? master of C programming? hell no, I still, even always to make mistake in coding just what I did in my very first codes, forget how to use the core features, code mistype, etc. Then what my improvements? my improvement is concept, a concept to understand how thing get works with this programming language, concept in how to use it's full abilities for solve programming complexity. And 5 years doesn't make enough time to be a master of a programming language, you will need 10 or more years for that, in two conditions, you must keep yourself using it, and you must keep learning it.
Dennis Ritchie (The Father of C, 1941 - 2011)
With those books, I had impressive proggress in C programming, I extend that improvement by learning real world's implementation such as Linux system and kernel programming upto GUI toolkit programming, then I start to write some simple program just for hobby. The hobby wouldn't keep me only for this, I also write a few of larger program to be released as free software. Surprisingly, they got some intentions and appreciation by the public.
And here I am, 5 years from the time I was learning. I don't know where I supposed to be if I didn't grab that book then start to write code in that time, I already wrote many simple upto big complex program using C. And what I got now? master of C programming? hell no, I still, even always to make mistake in coding just what I did in my very first codes, forget how to use the core features, code mistype, etc. Then what my improvements? my improvement is concept, a concept to understand how thing get works with this programming language, concept in how to use it's full abilities for solve programming complexity. And 5 years doesn't make enough time to be a master of a programming language, you will need 10 or more years for that, in two conditions, you must keep yourself using it, and you must keep learning it.
Dennis Ritchie (The Father of C, 1941 - 2011)
Monday, September 12, 2011
Simple gtkmm application development Makefile
I need to port a application from C to C++ with it's native GTK+ toolkit the gtkmm library. So here it's Makefile.
CC = g++
SOURCES = util.cc parser.cc net.cc main.cc
OBJECTS = ${SOURCES:.cc=.o}
CFLAGS = -Wall -c `pkg-config --cflags gtkmm-2.4`
LIBS = `pkg-config --libs gtkmm-2.4`
TARGET = tsc-utility
all: ${OBJECTS}
${CC} ${LIBS} ${OBJECTS} -o ${TARGET}
.cc.o:
${CC} ${CFLAGS} $<
clean:
rm -rf *.o ${TARGET}
CC = g++
SOURCES = util.cc parser.cc net.cc main.cc
OBJECTS = ${SOURCES:.cc=.o}
CFLAGS = -Wall -c `pkg-config --cflags gtkmm-2.4`
LIBS = `pkg-config --libs gtkmm-2.4`
TARGET = tsc-utility
all: ${OBJECTS}
${CC} ${LIBS} ${OBJECTS} -o ${TARGET}
.cc.o:
${CC} ${CFLAGS} $<
clean:
rm -rf *.o ${TARGET}
Friday, August 19, 2011
Custom PowerDNS Backend
So here I go, I was busy to develop PowerDNS custom pipe backend, why I develop this because it need:
Filtering: If you familiar with internet filtering service such as OpenDNS or a local service Nawala, they can block domain names based on defined criteria. With custom backend all DNS client's queries are send to the backend, give the backend flexable way to manage them. Filtering or blocking was done by bypassing DNS A (IPv4) or AAAA (IPv6) plus additional SOA record to the client.
Logging: All DNS queries need to be logged for statistics, to generate complex statistics data, log storage should be in structural format such as database.
So I called this backend with cpdns, stand for Custom PowerDNS Backend, cpdns need these following programs.
Short description about how the backend works, I'll divide backend's components based on their responsibility.
Query Parsing: PowerDNS
Pars
Filtering: If you familiar with internet filtering service such as OpenDNS or a local service Nawala, they can block domain names based on defined criteria. With custom backend all DNS client's queries are send to the backend, give the backend flexable way to manage them. Filtering or blocking was done by bypassing DNS A (IPv4) or AAAA (IPv6) plus additional SOA record to the client.
Logging: All DNS queries need to be logged for statistics, to generate complex statistics data, log storage should be in structural format such as database.
So I called this backend with cpdns, stand for Custom PowerDNS Backend, cpdns need these following programs.
- Redis: advanced memory database server, its has key-value concept to store data, perfect for distributed object caching.
- TCMalloc: fast and efficient memory allocator used by Redis.
- libunwind: C API used by TCMalloc.
- hiredis: Redis C client.
- libldns: C DNS library used by backend's resolver.
- MySQL: Famous RDBMS database to store domain filtering data and logs.
Short description about how the backend works, I'll divide backend's components based on their responsibility.
Query Parsing: PowerDNS
Pars
Friday, July 15, 2011
Scatter/gather I/O operation
This is a common way to do scatter/gather I/O (sometime called vectored I/O), it has great performance over large chunk of data. The readv() and writev() function are atomic means these system call only issued for once to transfer multiple data into the kernel.
unsigned len;
long iovcnt, iovcnt_max;
iovcnt_max = sysconf(_SC_IOV_MAX);
/* Determine how many part of data to be written */
while (len > 0) {
iovcnt = len >= iovcnt_max ? iovcnt_max : len;
struct iovec iov[iovcnt];
/* Initialize iov's members, process with readv() or writev() */
len -= iovcnt;
}
The above code first determine maximum allowed size of iovcnt, in Linux this value is 1024 but we should not rely on this but using system specific sysconf() function, after that the code determine struct iovec array and declare it as VLA and loop to write or read data until all data has been processed.
unsigned len;
long iovcnt, iovcnt_max;
iovcnt_max = sysconf(_SC_IOV_MAX);
/* Determine how many part of data to be written */
while (len > 0) {
iovcnt = len >= iovcnt_max ? iovcnt_max : len;
struct iovec iov[iovcnt];
/* Initialize iov's members, process with readv() or writev() */
len -= iovcnt;
}
The above code first determine maximum allowed size of iovcnt, in Linux this value is 1024 but we should not rely on this but using system specific sysconf() function, after that the code determine struct iovec array and declare it as VLA and loop to write or read data until all data has been processed.
Monday, November 22, 2010
Bit Packing
Last night I was busy hacking toll ticket, the application will be installed on a device that will be used for reading ticket when the power goes down. The problem is I must not using our ticket format for it, yeah in the name of vandalism. This word is very famous here. So we choose open Mifare Classic 1K card for that, open means with the standard transport key configuration.
The card need to hold some informations, the most important thing are shift (SH) and period (PR), vehicle classification (VC), plaza where the vehicle in (PI), post (PS), vehicle's direction (DR). We defined that maximum value for each information below all in integer type.
SH -> 0 - 3, 11 (2 bit), 11 or 0x3 as bitmask
PR -> 0 - 99, 1100011 (7 bit), 1111111 or 0x7f as bitmask
VC -> 0 - 5, 101 (3 bit), 111 or 0x7 as bitmask
PI -> 0 - 99, 1100011 (7 bit), 1111111 or 0x7f as bitmask
PS -> 0 - 99, 1100011 (7 bit), 1111111 or 0x7f as bitmask
DR -> 0 - 3, 11 (2 bit), 11 or 0x3 as bitmask
We have 28 bit, to construct them as integer we use the following as we already know
(SH & 0x3) << 26 | (PR & 0x7f) << 19 | (VC & 0x7) << 16 | (PI & 0x7f) << 9 | (PS & 0x7f) << 2 | (DR & 0x3)
For extracting those integers we use
SH = value >> 26 & 0x3
PR = value >> 19 & 0x7f
VC = value >> 16 & 0x3
PI = value >> 9 & 0x7f
PS = value >> 2 & 0x7f
DR = value & 0x3
This is only a simple bit operation that sometime we forgot how they are works, so here the source code, it need ACR120 communication library to be compiled.
The card need to hold some informations, the most important thing are shift (SH) and period (PR), vehicle classification (VC), plaza where the vehicle in (PI), post (PS), vehicle's direction (DR). We defined that maximum value for each information below all in integer type.
SH -> 0 - 3, 11 (2 bit), 11 or 0x3 as bitmask
PR -> 0 - 99, 1100011 (7 bit), 1111111 or 0x7f as bitmask
VC -> 0 - 5, 101 (3 bit), 111 or 0x7 as bitmask
PI -> 0 - 99, 1100011 (7 bit), 1111111 or 0x7f as bitmask
PS -> 0 - 99, 1100011 (7 bit), 1111111 or 0x7f as bitmask
DR -> 0 - 3, 11 (2 bit), 11 or 0x3 as bitmask
We have 28 bit, to construct them as integer we use the following as we already know
(SH & 0x3) << 26 | (PR & 0x7f) << 19 | (VC & 0x7) << 16 | (PI & 0x7f) << 9 | (PS & 0x7f) << 2 | (DR & 0x3)
For extracting those integers we use
SH = value >> 26 & 0x3
PR = value >> 19 & 0x7f
VC = value >> 16 & 0x3
PI = value >> 9 & 0x7f
PS = value >> 2 & 0x7f
DR = value & 0x3
This is only a simple bit operation that sometime we forgot how they are works, so here the source code, it need ACR120 communication library to be compiled.
Saturday, July 10, 2010
TCT's cycle time algorithm
This is a code that describes TCT cycle algorithm, the first method is by using a thread, i don't know why i should use the unimportant thread in the past. However, this is the newest and improved code.
http://pastebin.com/raw.php?i=ZgLh7k7A
PS. I wrote these without the fucking smokes, what a progress.
http://pastebin.com/raw.php?i=ZgLh7k7A
PS. I wrote these without the fucking smokes, what a progress.
Wednesday, June 16, 2010
TCT Tool
TCT Tool is a application that do some privileged tasks in the TCT machine. By default, TCT run in non-privileged mode so it can't do for example sending ioctl to the ethernet driver, update the system time, and many more. They use POSIX message queue for communication. Thanks for Glynn Clements at linux-c-programming who helped me out with message queue descriptor permission.
http://pastebin.com/raw.php?i=x4X6G4uf
http://pastebin.com/raw.php?i=x4X6G4uf
Monday, March 22, 2010
UNIX exec family system call
This codes creating pipe for IPC, fork another process (child) and executing fortune with some cookies arguments. It also redirect child's stdout to it's writer pipe to be read by parent's pipe. exec() family calls never return except for errors, if this happen it is very bad ;p. exec() will replace it's calling process with a new image, since the kernel is not know where to continue after invoking exec() then the child just exit. Just to make sure you don't write codes after that exec() except for error checking, don't care how cool your codes, it just not work. Trust me heh?.
http://pastebin.com/raw.php?i=pceQuWjc
http://pastebin.com/raw.php?i=pceQuWjc
Sunday, January 24, 2010
C gibberish
When reading a question in the Linux Kernel Mailing lists section linux-c-programming, someone ask about the means of this code
char (*pa())[4];
Someone else ask him to use cdcel a small utility that translate C syntax into human readable words. For example consider this code
int (*sched_callback) (pid_t, struct sched_param*);
this means
declare sched_callback as pointer to function (pid_t, pointer to struct sched_param) returning int
Here a short description about cdecl
By the way, the answer of his question according to cdecl is
declare pa as function returning pointer to array 4 of char
Give it a try, it's perfect for deep understanding the C language.
http://www.cdecl.org/
char (*pa())[4];
Someone else ask him to use cdcel a small utility that translate C syntax into human readable words. For example consider this code
int (*sched_callback) (pid_t, struct sched_param*);
this means
declare sched_callback as pointer to function (pid_t, pointer to struct sched_param) returning int
Here a short description about cdecl
Cdecl is a program which will turn English-like phrases such as "declare foo as array 5 of pointer to function returning int" into C declarations such as "int (*foo[5])()". It can also translate the C into the pseudo-English. And it handles typecasts, too. Plus C++. And in this version it has command line editing and history with the GNU readline library.
By the way, the answer of his question according to cdecl is
declare pa as function returning pointer to array 4 of char
Give it a try, it's perfect for deep understanding the C language.
http://www.cdecl.org/
Thursday, October 29, 2009
Bit masking

As system, kernel and device driver programmer, you, of course use heavy of bitwise operation. This is a simple C code demonstrate bit masking and it's use in the real world ;), see also bit packing/unpacking for more fun.
#include <stdio.h>
enum {
SANDRA = 1 << 0,
DESSY = 1 << 1,
YANA = 1 << 2,
SUSAN = 1 << 3
};
void print(unsigned char val)
{
printf("val: %u\n", val);
printf("SANDRA loves me: %i\n", (val & SANDRA) ? 1 : 0);
printf("DESSY loves me: %i\n", (val & DESSY) ? 1 : 0);
printf("YANA loves me: %i\n", (val & YANA) ? 1 : 0);
printf("SUSAN loves me: %i\n", (val & SUSAN) ? 1 : 0);
}
int main(void)
{
unsigned char val = 0;
val = SANDRA | DESSY | YANA;
print(val);
printf("\n");
val &= ~SANDRA;
print(val);
printf("\n");
val &= ~(DESSY | YANA);
val |= (SUSAN | SANDRA);
print(val);
printf("\n");
val &= ~(SANDRA | DESSY | YANA | SUSAN);
print(val);
return 0;
}
Wednesday, October 07, 2009
GCC -g option
Glynn Clements answer an email in the linux-c-programming mailing list to someone who ask about GCC -g option
Glynn Clements is an active member in the Linux's kernel mailing list, i love the way he answer a question.
Most the time I compile my application without the -g option due to performance reasons.
The -g switch has absolutely no effect upon performance. It simply causes and additional section to be added to the resulting binary. When the program is run normally (i.e. not under gdb), that section won't be mapped. The only downside to -g is that it increases the size
of the file.
However: debug information isn't necessarily much help if you compile with optimisation enabled, as the resulting machine code will bear little resemblance to the original source code. Statements will be re-ordered, many variables will be eliminated, etc.
Problem is that when it hits some bug and dumps core, this is not very useful because there is hardly any information in it. Is there some way to get some useful information out of the core file. For example one of my program crashed and with gdb I see the following: At least I know that the bug is in my function start_process. But is there some way to find out at what line it happened?
It isn't meaningful to talk about a "line" in the source code if you compile with optimisation enabled. However, you can tell gdb to disassemble the machine code for a particular function, and you can print the values contained in registers or at specific memory locations. Working out what that information means in terms of the source code is something which needs to be done manually.
Glynn Clements is an active member in the Linux's kernel mailing list, i love the way he answer a question.
Friday, October 02, 2009
GCC C Extension
This is the GNU C Compiler extension for the C programming language.
Arithmetic on void- and Function-Pointers
In GNU C, addition and subtraction operations are supported on pointers to void and on pointers to functions. This is done by treating the size of a void or of a function as 1.
A consequence of this is that sizeof is also allowed on void and on function types, and returns 1.
The option -Wpointer-arith requests a warning if these extensions are used.
Example:
void *ptr;
/* validate ptr pointer */
func(ptr + 2);
Non-Constant Initializers
As in standard C++, the elements of an aggregate initializer for an automatic variable are not required to be constant expressions in GNU C. Here is an example of an initializer with run-time varying elements:
foo (float f, float g)
{
float beat_freqs[2] = { f-g, f+g };
...
}
Nested Functions
A nested function is a function defined inside another function. (Nested functions are not supported for GNU C++.) The nested function's name is local to the block where it is defined. For example, here we define a nested function named square, and call it twice:
foo (double a, double b)
{
double square(double z) { return z * z; }
return square(a) + square(b);
}
The nested function can access all the variables of the containing function that are visible at the point of its definition. This is called lexical scoping. For example, here we show a nested function which uses an inherited variable named offset:
bar (int *array, int offset, int size)
{
int access(int *array, int index)
{ return array[index + offset]; }
int i;
...
for (i = 0; i < size; i++)
... access(array, i) ...
}
64 Bit Integer
GCC support 64 bit integer value with long long type. Example:
unsigned long long value64 = 23ULL;
unsigned long value32 = 23UL;
printf("sizeof(value64) is %i bit\n", sizeof(value64) << 3);
printf("sizeof(value32) is %i bit\n", sizeof(value32) << 3);
http://gcc.gnu.org
Arithmetic on void- and Function-Pointers
In GNU C, addition and subtraction operations are supported on pointers to void and on pointers to functions. This is done by treating the size of a void or of a function as 1.
A consequence of this is that sizeof is also allowed on void and on function types, and returns 1.
The option -Wpointer-arith requests a warning if these extensions are used.
Example:
void *ptr;
/* validate ptr pointer */
func(ptr + 2);
Non-Constant Initializers
As in standard C++, the elements of an aggregate initializer for an automatic variable are not required to be constant expressions in GNU C. Here is an example of an initializer with run-time varying elements:
foo (float f, float g)
{
float beat_freqs[2] = { f-g, f+g };
...
}
Nested Functions
A nested function is a function defined inside another function. (Nested functions are not supported for GNU C++.) The nested function's name is local to the block where it is defined. For example, here we define a nested function named square, and call it twice:
foo (double a, double b)
{
double square(double z) { return z * z; }
return square(a) + square(b);
}
The nested function can access all the variables of the containing function that are visible at the point of its definition. This is called lexical scoping. For example, here we show a nested function which uses an inherited variable named offset:
bar (int *array, int offset, int size)
{
int access(int *array, int index)
{ return array[index + offset]; }
int i;
...
for (i = 0; i < size; i++)
... access(array, i) ...
}
64 Bit Integer
GCC support 64 bit integer value with long long type. Example:
unsigned long long value64 = 23ULL;
unsigned long value32 = 23UL;
printf("sizeof(value64) is %i bit\n", sizeof(value64) << 3);
printf("sizeof(value32) is %i bit\n", sizeof(value32) << 3);
http://gcc.gnu.org
Friday, September 04, 2009
Bit packing/upacking

Our TCT require to store and read information on a smartcard, each transaction, officer and engineer identification will use a smartcard. For example to store and read transaction information the card management use a value block, it's a 32 bit unsigned integer, some informations will be packed into this integer, for example with this informations:
MSB LSB
5 bit | 6 bit | 4 bit | 6 bit | 8 bit | 3 bit (32 bit integer)
info1 | info2 | info3 | info4 | info5 | info6
Given the value for 0xa082abc8 or 2692918216 in decimal, to unpack the informations we simply do bit shift and masking:
info1 = value >> 27 & 0x1f;
info2 = value >> 21 & 0x3f;
info3 = value >> 17 & 0xf;
info4 = value >> 11 & 0x3f;
info5 = value >> 3 & 0xff;
info6 = value & 0x7;
and for packing from the informations:
((info1 & 0x1f) << 27) | ((info2 & 0x3f) << 21) | ((info3 & 0xf) << 17) | ((info4 & 0x3f) << 11) | ((info5 & 0xff) << 3) | (info6 & 0x7)
another way is to create bitfield, as follow:
union {
struct {
unsigned int info6 : 3;
unsigned int info5 : 8;
unsigned int info4 : 6;
unsigned int info3 : 4;
unsigned int info2 : 6;
unsigned int info1 : 5;
} bit;
unsigned int val
} data;
The bitfield already packed, so we only need to assign a value to val member and access bitfield info member as informations. To assign a bitfield member, it's like we do in a generic C structure. But be carefull with bitfield, different machine maybe has different a byte-order convention. Intel CPU follow litle-endian and other CPU like Motorola use big-endian convention, the above bitfield was intended to be use in a litle-endian system, if you want more portable code use bit shifting and masking, for bitfield, use compiler preprocessor directive such as __LITTLE_ENDIAN in GCC.
http://en.wikipedia.org/wiki/Bit_field
http://en.wikipedia.org/wiki/Endianness
Tuesday, July 21, 2009
C++ Notes
Well, this is my C++ notes collections, might be useful for anyone who want to learning the C++ programming language. Most of these codes have been compiled with GNU C++ Compiler under Linux system, but i think it will also run on different compiler and system.
class-inheritance.cc
type.cc
static-member.cc
overload1.cc
friend-function.cc
friend-class.cc
class-inheritance.cc
type.cc
static-member.cc
overload1.cc
friend-function.cc
friend-class.cc
Thursday, May 21, 2009
Linus hate C++

Linus said:
C++ is a horrible language. It's made more horrible by the fact that a lot of substandard programmers use it, to the point where it's much much easier to generate total and utter crap with it.
C++ is in that inconvenient spot where it doesn't help make things simple enough to be truly usable for prototyping or simple GUI programming, and yet isn't the lean system programming language that C is that actively encourages you to use simple and direct constructs.
Wednesday, May 13, 2009
Cool pointer
Have you try a code like this?
int main (void)
{
int date[12][31];
int (*m)[31];
int *d;
for (m = date; m < &date[12]; m++)
{
**m = 0;
for (d = *m; d < &(*m)[31]; d++)
*d = 0;
}
return 0;
}
int main (void)
{
int date[12][31];
int (*m)[31];
int *d;
for (m = date; m < &date[12]; m++)
{
**m = 0;
for (d = *m; d < &(*m)[31]; d++)
*d = 0;
}
return 0;
}
Wednesday, April 22, 2009
Defensive Programming
I'm now reading "Defensive Programming for Red Hat Enterprise Linux" by Ulrich Drepper, of course not only for RHEL but for every Linux system and programmer who think security is a big issue.
Ulrich Drepper's Website
Ulrich Drepper's Website
Sunday, March 29, 2009
Socket Programming: Dynamic sized data
I have been posted on linux-c-programming@vger.kernel.org regarding receiving dynamic size data using TCP/IP socket, and now resolved:
struct foo {
char *name;
unsigned int id;
};
int ret, len;
struct foo *bar = malloc (sizeof(struct foo));
/* fill bar */
len = strlen (name);
send (s, &len, sizeof(len), 0);
send (s, bar->name, len, 0);
send (s, &bar->id, sizeof(bar->id), 0);
And for the receiver:
recv (s, &len, sizeof(len), 0);
/* allocate bar->name for len bytes */
recv (s, bar->name, len, 0);
Notice there are no error checking and network byte ordering here.
struct foo {
char *name;
unsigned int id;
};
int ret, len;
struct foo *bar = malloc (sizeof(struct foo));
/* fill bar */
len = strlen (name);
send (s, &len, sizeof(len), 0);
send (s, bar->name, len, 0);
send (s, &bar->id, sizeof(bar->id), 0);
And for the receiver:
recv (s, &len, sizeof(len), 0);
/* allocate bar->name for len bytes */
recv (s, bar->name, len, 0);
Notice there are no error checking and network byte ordering here.
Friday, January 23, 2009
Survey: C adalah bahasa programming yang mendominasi proyek open-source
Dari Slashdot, Survey Says C dominated New '08 Open-Source Projects, C adalah bahasa programming yang mendominasi proyek open-source tahun 2008 dari laporan The Register (UK). Menurut Black Duck Software yang memonitor 180000 proyek pada hampir 4000 website, hampir setengah - 47% - 17000 dari proyek open-source yang baru ditulis dalam bahasa C. Setelah itu Java sebesar 28%. Untuk bahasa scripting JavaScript menempati posisi teratas sebesar 20%, lalu Perl 18%, PHP sebesar 11% dan Ruby hanya sebesar 6%. PHP banyak lebih banyak digunakan untuk development website ketimbang Ruby.
Dari kutipan diatas, C adalah bahasa yang paling universal. Bahasa ini bisa untuk hampir semua level pemrograman. Kernel Linux sebagian besarnya ditulis dengan bahasa C, untuk GUI ada toolkit GTK+ di UNIX dan WinAPI di Windows. C dengan GTK+ tercapai karena implementasi sistem obyek pada level C yang disebut dengan GObject. Ini adalah inti C dan GTK+ di desktop GNOME. Saya sangat menyukai C tapi ingin mempelajari bahasa-bahasa yang baru lebih dalam juga. Python dan C# (mono) adalah pilihan yang baik.
Dari kutipan diatas, C adalah bahasa yang paling universal. Bahasa ini bisa untuk hampir semua level pemrograman. Kernel Linux sebagian besarnya ditulis dengan bahasa C, untuk GUI ada toolkit GTK+ di UNIX dan WinAPI di Windows. C dengan GTK+ tercapai karena implementasi sistem obyek pada level C yang disebut dengan GObject. Ini adalah inti C dan GTK+ di desktop GNOME. Saya sangat menyukai C tapi ingin mempelajari bahasa-bahasa yang baru lebih dalam juga. Python dan C# (mono) adalah pilihan yang baik.
Subscribe to:
Posts (Atom)