for(;...) or while(...) flow control? [closed] - c

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Which one, 1 or 2, is better in any way (whatever can be considered better)? Are they exactly the same?
void method1(char **var1) {
//the last element of var1 is NULL
char **var2 = var1;
int count = 0;
//1
for (; *var2; (*var2)++, count++);
//2
while(*var2) {
(*var2)++;
count++;
}
}

you could examine the asm output at different optimization levels with your compiler... or just not worry about stuff that is semantically the same...
...
LBB0_1: ## =>This Inner Loop Header: Depth=1
movq -16(%rbp), %rax
cmpq $0, (%rax)
je LBB0_4
## BB#2: ## in Loop: Header=BB0_1 Depth=1
jmp LBB0_3
LBB0_3: ## in Loop: Header=BB0_1 Depth=1
movq -16(%rbp), %rax
movq (%rax), %rcx
addq $1, %rcx
movq %rcx, (%rax)
movl -20(%rbp), %edx
addl $1, %edx
movl %edx, -20(%rbp)
jmp LBB0_1
LBB0_4:
...
.subsections_via_symbols
method2:
...
LBB0_1: ## =>This Inner Loop Header: Depth=1
movq -16(%rbp), %rax
cmpq $0, (%rax)
je LBB0_3
## BB#2: ## in Loop: Header=BB0_1 Depth=1
movq -16(%rbp), %rax
movq (%rax), %rcx
addq $1, %rcx
movq %rcx, (%rax)
movl -20(%rbp), %edx
addl $1, %edx
movl %edx, -20(%rbp)
jmp LBB0_1
LBB0_3:
...
.subsections_via_symbols

Purpose of the code in question
Your code seems to be entirely wrong as it increments the target of var2 pointer, which also serves for ending the loop. You cannot expect an incrementing value to reach zero. I will assume that (1) you wanted to increment the temporary pointer to iterate over a list (technically an array) of character strings and (2) that you expect a NULL pointer as a sentinel.
Detailed explanation of the pointer incrementation issue
So what is the logic of the code we are writing? It takes an array of strings (lines in a file, list of names, etc...), counts the items, and then does whatever else you need to do. The input argument is represented by a pointer to pointer to char, which can be a bit confusing for the beginner. Pointers are used for multiple purposes in C and one is to point to the first item of a list (technically array). This is the case of the list pointer (type char **) which points to an array of pointers (type char * each) which in turn point to an array of byte/character values (type char each).
Therefore you need to increment a local char ** pointer to iterate over the items and a temporary char * pointer to iterate over characters of an item. If you just want to read data, you must never increment anything else than local (temporary) variables. Incrementing *item is nonsense and would alter the data in a bad way (the pointer would point to the second character instead of the first one), and checking the incremented pointer for being NULL is a double nonsense.
In other words, the idiom of iterating over an array using a temporary pointer requires the following actions:
Increment the temporary pointer (and nothing else) at each step.
Check the target of the pointer (and not the address it points to) for the sentinel value.
Corrected code examples
Using C99 syntax, you probably wanted to do something like:
void method1(char **list) {
size_t count = 0;
for (char **item = list; *item; item++)
count++;
...
}
The older syntax is forcing you to do:
void method1(char **list) {
char **item;
size_t count = 0;
for (item = list; *item; item++)
count++;
...
}
A more intuitive version for people not fluent in pointers:
void method1(char **list) {
size_t count = 0;
for (size_t i = 0; list[i]; i++)
count++;
...
}
Note: The count is redundant as its value is kept the same as the value of i, so you could just do for (; list[count]; count++) with an empty body or while (list[count]) count++;.
A real function to just count the items would be:
size_t get_size(char **list)
{
int count = 0;
for (char **item = list; *item; item++)
count++;
return count;
}
Of course it could be simplified to (borrowing from other answer):
size_t get_size(char **list)
{
int count = 0;
for (; *list; list++)
count++;
return count;
}
Thanks to very specific circumstances where (1) it's easy to merge the condition and the increment and (2) you're not using the current item in the body, it can be turned to:
size_t get_size(char **list)
{
int count = 0;
while (*list++)
count++;
return count;
}
Attempt to answer the for versus while dilemma
While technically the while and for loops are equivalent, the for loop expresses the iteration idiom way better, as it keeps the iteration logic separate from the rest of the code and thus also makes it more reusable, i.e. you can use the same for header with a different body for any other iterative action on the list.
Bad usage of the for loop in the original code
There are a number of things that should be considered discouraged:
1) Don't modify the object from the for loop header.
for (... ; ...; (*item)++)
...
Any code matching the above patter modifies the target object instead of performing the looping logic, whenever item is a temporary pointer to the actual data.
2) Don't decouple any non-looping code from the for loop header.
char **item = list;
...
for (; *item; *item++)
count++;
The assignment before the for loop seems out of place. If you copy-pasted the header of the for loop to iterate again over all list items, the list would seem empty because of the omitted initialization.
3) Don't perform any per-item actions in the increment of the for loop header.
for (char **item = list; *item++, count++)
;
The count++ here doesn't help the looping at all, instead it performs an actual action (counting one item). If you copy-pasted the header of the for loop and added an actual body, the count would get modified.
4) Don't use non-descriptive for arguments, use simple names for temporary variables.
for (char **var2 = var1; *var2; var2++)
count++;
The two variables differ in their purpose, yet their names are almost the same, only distinguished by a number. How exactly you name them is a matter of context and preference.
Note: Some people also prefer explicit comparison to NULL instead of relying on boolean evaluation of pointers. I'm not one of them, though. Stack Exchange seems to highlight list as a keyword but I don't think there's such a keyword in C or C++.

I would prefer the for loop, if you initialize var2 as the first argument of the for loop, i.e.
for(char **var2 = var1; *var2; var2++)
because then all conditions (initial, terminal, increment) are located in one place
I would also prefer to make the test explicit, i.e.,
for(char **var2 = var1; *var2 != NULL; var2++)
because it makes the terminal condition more visible.
Next: I would not place count++ in the for loop, because if count is not modified inside the loop it is redundant and can be calculated from var2 - var 1. If count is modified inside the loop it should be done at a single spot.
But I assume this is a matter of taste only.

Probably both are same, compiler should not make any difference.

First of all the both loops are wrong. They have no sense. I think you mean the following
int count = 0;
while ( *var1++ ) ++count;
It is the loop I would use.
Or if you want that var1 would not be changed then
int count = 0;
for ( char **p = var1; *p; ++p ) ++count;
Also you could write
char **p = var1;
while ( *p ) ++p;
int count = p - var1;

you better make the loop conditional statement more stronger and explicit to avoid bugs and infinity loops. which one is better depends in your logic and code, "for" loops is faster and easier but if you want to make a loop which needs more logic then use "while" loop.

Related

How to change the local variable without its reference

Interview question : Change the local variable value without using a reference as a function argument or returning a value from the function
void func()
{
/*do some code to change the value of x*/
}
int main()
{
int x = 100;
printf("%d\n", x); // it will print 100
func(); // not return any value and reference of x also not sent
printf("%d\n", x); // it need to print 200
}
x value need to changed
The answer is that you can’t.
The C programming language offers no way of doing this, and attempting to do so invariably causes undefined behaviour. This means that there are no guarantees about what the result will be.
Now, you might be tempted to exploit undefined behaviour to subvert C’s runtime system and change the value. However, whether and how this works entirely depends on the specific executing environment. For example, when compiling the code with a recent version of GCC and clang, and enabling optimisation, the variable x simply ceases to exist in the output code: There is no memory location corresponding to its name, so you can’t even directly modify a raw memory address.
In fact, the above code yields roughly the following assembly output:
main:
subq $8, %rsp
movl $100, %esi
movl $.LC0, %edi
xorl %eax, %eax
call printf
xorl %eax, %eax
call func
movl $100, %esi
movl $.LC0, %edi
xorl %eax, %eax
call printf
xorl %eax, %eax
addq $8, %rsp
ret
As you can see, the value 100 is a literal directly stored in the ESI register before the printf call. Even if your func attempted to modify that register, the modification would then be overwritten by the compiled printf call:
…
movl $200, %esi /* This is the inlined `func` call! */
movl $100, %esi
movl $.LC0, %edi
xorl %eax, %eax
call printf
…
However you dice it, the answer is: There is no x variable in the compiled output, so you cannot modify it, even accepting undefined behaviour. You could modify the output by overriding the printf function call, but that wasn’t the question.
By the design of the C language, and by the definition of a local variable, you cannot access it from outside without making it available in some way.
Some ways to make a local variable accessible to the outside world:
send a copy of it (the value);
send a pointer to it (don't save and use the pointer for too long, since the variable may be removed when its scope ends);
export it with extern if the variable is declared at file level (outside of all functions).
Hack
Only changing code in void func(), create a define.
Akin to #chqrlie.
void func()
{
/*do some code to change the value of x*/
#define func() { x = 200; }
}
int main()
{
int x = 100;
printf("%d\n", x); // it will print 100
func(); // not return any value and reference of x also not sent
printf("%d\n", x); // it need to print 200
}
Output
100
200
The answer is that you can’t, but...
I perfectly agree with what #virolino and #Konrad Rudolph and I don't like my "solution" to this problem be recognised as a best practise, but since this is some sort of challenge one can come up with this approach.
#include <stdio.h>
static int x;
#define int
void func() {
x = 200;
}
int main() {
int x = 100;
printf("%d\n", x); // it prints 100
func(); // not return any value and reference of x also not sent
printf("%d\n", x); // it prints 200
}
The define will set int to nothing. Thus x will be the global static x and not the local one. This compiles with a warning, since the line int main() { is now only main(){. It only compiles due to the special handling of a function with return type int.
This approach is hacky and fragile, but that interviewer is asking for it. So here's an example for why C and C++ are such fun languages:
// Compiler would likely inline it anyway and that's necessary, because otherwise
// the return address would get pushed onto the stack as well.
inline
void func()
{
// volatile not required here as the compiler is told to work with the
// address (see lines below).
int tmp;
// With the line above we have pushed a new variable onto the stack.
// "volatile int x" from main() was pushed onto it beforehand,
// hence we can take the address of our tmp variable and
// decrement that pointer in order to point to the variable x from main().
*(&tmp - 1) = 200;
}
int main()
{
// Make sure that the variable doesn't get stored in a register by using volatile.
volatile int x = 100;
// It prints 100.
printf("%d\n", x);
func();
// It prints 200.
printf("%d\n", x);
return 0;
}
Boring answer: I would use a straightforward, global pointer variable:
int *global_x_pointer;
void func()
{
*global_x_pointer = 200;
}
int main()
{
int x = 100;
global_x_pointer = &x;
printf("%d\n", x);
func();
printf("%d\n", x);
}
I'm not sure what "sending reference" means. If setting a global pointer counts as sending a reference, then this answer obviously violates the stated problem's curious stipulations and isn't valid.
(On the subject of "curious stipulations", I've sometimes wished SO had another tag, something like driving-screws-with-a-hammer, because that's what these "brain teasers" always make me think of. Perfectly obvious question, perfectly obvious answer, but no, gotcha, you can't use that answer, you're stuck on a desert island and your C compiler's for statement got broken in the shipwreck, so you're supposed to be McGyver and use a coconut shell and a booger instead. Occasionally these questions can demonstrate good lateral thinking skills and are interesting, but most of the time, they're just dumb.)

Array of pointers - need bigger

How can I create an array of pointers that can store more than 1,047,141 pointers? I calculated this number using the following code:
int main(int argc, char const *argv[]) {
long a = 0;
while(1==1){
char * str[a];
printf("%ld is good.\n", a);
a++;
//Loop ends on Segmentation fault
}
return 0;
}
I am using the array of pointers to store strings. What are the alternatives?
Edit
The code above is just a way of finding the max size of an array of pointers.
One pointer holds one string, so the max number of strings I can store is 1,047,141. I need a way of storing more than 1,047,141 strings.
Allocate the array dynamically via malloc().
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
long a = 0;
while(1==1){
char ** str = malloc(sizeof(char*) * a);
if (str != NULL){
printf("%ld is good.\n", a);
free(str);
} else {
break;
}
a++;
}
return 0;
}
You have to allocate the arrays on the heap with malloc. This code will allocate an array of pointers long how_many_strings; and for each pointer it will allocate a string long str_length.
char** str = malloc(sizeof(char*)*how_many_strings);
for(int i = 0; i < how_many_strings; i++)
{
str[i] = malloc(sizeof(char)*str_length);
}
The size is limited to your RAM capacity.
The OP code has undefined behavior. The array isn't used, so if you use -O2 (gcc), you are just printing a as it increments. Gcc generates:
.L2:
movq %rbx, %rdx
movl $.LC0, %esi
movl $1, %edi
xorl %eax, %eax
addq $1, %rbx
call __printf_chk
jmp .L2
It won't segfault, but the output will be quite boring.
However, with -O0, gcc generates a much longer loop (that I don't want to paste) that creates larger and larger str buffers on the stack. At some point when running this you will run out of stack space, which can cause a segfault.

divide and store quotient and reminder in different arrays

The standard div() function returns a div_t struct as parameter, for example:
/* div example */
#include <stdio.h> /* printf */
#include <stdlib.h> /* div, div_t */
int main ()
{
div_t divresult;
divresult = div (38,5);
printf ("38 div 5 => %d, remainder %d.\n", divresult.quot, divresult.rem);
return 0;
}
My case is a bit different; I have this
#define NUM_ELTS 21433
int main ()
{
unsigned int quotients[NUM_ELTS];
unsigned int remainders[NUM_ELTS];
int i;
for(i=0;i<NUM_ELTS;i++) {
divide_single_instruction(&quotient[i],&reminder[i]);
}
}
I know that the assembly language for division does everything in single instruction, so I need to do the same here to save on cpu cycles, which is bassicaly move the quotient from EAX and reminder from EDX into a memory locations where my arrays are stored. How can this be done without including the asm {} or SSE intrinsics in my C code ? It has to be portable.
Since you're writing to the arrays in-place (replacing numerator and denominator with quotient and remainder) you should store the results to temporary variables before writing to the arrays.
void foo (unsigned *num, unsigned *den, int n) {
int i;
for(i=0;i<n;i++) {
unsigned q = num[i]/den[i], r = num[i]%den[i];
num[i] = q, den[i] = r;
}
}
produces this main loop assembly
.L5:
movl (%rdi,%rcx,4), %eax
xorl %edx, %edx
divl (%rsi,%rcx,4)
movl %eax, (%rdi,%rcx,4)
movl %edx, (%rsi,%rcx,4)
addq $1, %rcx
cmpl %ecx, %r8d
jg .L5
There are some more complicated cases where it helps to save the quotient and remainder when they are first used. For example in testing for primes by trial division you often see a loop like this
for (p = 3; p <= n/p; p += 2)
if (!(n % p)) return 0;
It turns out that GCC does not use the remainder from the first division and therefore it does the division instruction twice which is unnecessary. To fix this you can save the remainder when the first division is done like this:
for (p = 3, q=n/p, r=n%p; p <= q; p += 2, q = n/p, r=n%p)
if (!r) return 0;
This speeds up the result by a factor of two.
So in general GCC does a good job particularly if you save the quotient and remainder when they are first calculated.
The general rule here is to trust your compiler to do something fast. You can always disassemble the code and check that the compiler is doing something sane. It's important to realise that a good compiler knows a lot about the machine, often more than you or me.
Also let's assume you have a good reason for needing to "count cycles".
For your example code I agree that the x86 "idiv" instruction is the obvious choice. Let's see what my compiler (MS visual C 2013) will do if I just write out the most naive code I can
struct divresult {
int quot;
int rem;
};
struct divresult divrem(int num, int den)
{
return (struct divresult) { num / den, num % den };
}
int main()
{
struct divresult res = divrem(5, 2);
printf("%d, %d", res.quot, res.rem);
}
And the compiler gives us:
struct divresult res = divrem(5, 2);
printf("%d, %d", res.quot, res.rem);
01121000 push 1
01121002 push 2
01121004 push 1123018h
01121009 call dword ptr ds:[1122090h] ;;; this is printf()
Wow, I was outsmarted by the compiler. Visual C knows how division works so it just precalculated the result and inserted constants. It didn't even bother to include my function in the final code. We have to read in the integers from console to force it to actually do the calculation:
int main()
{
int num, den;
scanf("%d, %d", &num, &den);
struct divresult res = divrem(num, den);
printf("%d, %d", res.quot, res.rem);
}
Now we get:
struct divresult res = divrem(num, den);
01071023 mov eax,dword ptr [num]
01071026 cdq
01071027 idiv eax,dword ptr [den]
printf("%d, %d", res.quot, res.rem);
0107102A push edx
0107102B push eax
0107102C push 1073020h
01071031 call dword ptr ds:[1072090h] ;;; printf()
So you see, the compiler (or this compiler at least) already does what you want, or something even more clever.
From this we learn to trust the compiler and only second-guess it when we know it isn't doing a good enough job already.

Segmentation fault creating a user-level thread with C and assembly

I am trying to understand some OS fundamentals using some assignments. I have already posted a similar question and got satisfying answers. But this one is slightly different but I haven't been able to debug it. So here's what I do:
What I want to do is to start a main program, malloc a space, use it as a stack to start a user-level thread. My problem is with return address. Here's the code so far:
[I'm editing my code to make it up-to-date to the current state of my answer ]
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define STACK_SIZE 512
void switch_thread(int*,int*);
int k = 0;
void simple_function()
{
printf("I am the function! k is: %d\n",k);
exit(0);
}
void create_thread(void (*function)())
{
int* stack = malloc(STACK_SIZE + 32);
stack = (int* )(((long)stack & (-1 << 4)) + 0x10);
stack = (int* ) ((long)stack + STACK_SIZE);
*stack = (long) function;
switch_thread(stack,stack);
}
int main()
{
create_thread(simple_function);
assert(0);
return 0;
}
switch_thread is an assembly code I've written as follows:
.text
.globl switch_thread
switch_thread:
movq %rdi, %rsp
movq %rsi, %rbp
ret
This code runs really well under GDB and gives the expected output (which is,passing the control to simple_function and printing "I am the function! k is: 0". But when run separately, this gives a segmentation fault. I'm baffled by this result.
Any help would be appreciated. Thanks in advance.
Two problems with your code:
Unless your thread is actually inside a proper procedure (or a nested procedure), there's no such thing as "base pointer". This makes the value of %rbp irrelevant since the thread is not inside a particular procedure at the point of initialization.
Contrary to what you think, when the ret instruction gets executed, the value that %rsp is referring to becomes the new value of the program counter. This means that instead of *(base_pointer + 1), *(base_pointer) will be consulted when it gets executed. Again, the value of %rbp is irrelevant here.
Your code (with minimal modification to make it run) should look like this:
void switch_thread(int* stack_pointer,int* entry_point);
void create_thread(void (*function)())
{
int* stack_pointer = malloc(STACK_SIZE + 8);
stack_pointer += STACK_SIZE; //you'd probably want to back up the original allocated address if you intend to free it later for any reason.
switch_thread(stack_pointer,function);
}
Your switch_thread routine should look like this:
.text
.globl switch_thread
switch_thread:
mov %rsp, %rax //move the original stack pointer to a scratch register
mov %rdi, %rsp //set stack pointer
push %rax //back-up the original stack pointer
call %rsi //call the function
pop %rsp //restore the original stack pointer
ret //return to create_thread
FYI: If you're initializing a thread on your own, I suggest that you first create a proper trampoline that acts as a thread entry point (e.g. ntdll's RtlUserThreadStart). This will make things much cleaner especially if you want to make your program multithreaded and also pass in any parameters to the start routine.
base_pointer needs to be suitably aligned to store void (*)() values, otherwise you're dealing with undefined behaviour. I think you mean something like this:
void create_thread(void (*function)())
{
size_t offset = STACK_SIZE + sizeof function - STACK_SIZE % sizeof function;
char *stack_pointer = malloc(offset + sizeof *base_pointer);
void (**base_pointer)() = stack_pointer + offset;
*base_pointer = function;
switch_thread(stack_pointer,base_pointer);
}
There is no need to cast malloc. It's generally a bad idea to cast pointers to integer types, or function pointers to object pointer types.
I understand that this is all portable-C nit-picky advice, but it really does help to write as much as your software as possible in portable code rather than relying upon undefined behaviour.

Multithreading with inline assembly and access to a c variable

I'm using inline assembly to construct a set of passwords, which I will use to brute force against a given hash. I used this website as a reference for the construction of the passwords.
This is working flawlessly in a singlethreaded environment. It produces an infinite amount of incrementing passwords.
As I have only basic knowledge of asm, I understand the idea. The gcc uses ATT, so I compile with -masm=intel
During the attempt to multithread the program, I realize that this approach might not work.
The following code uses 2 global C variables, and I assume that this might be the problem.
__asm__("pushad\n\t"
"mov edi, offset plaintext\n\t" <---- global variable
"mov ebx, offset charsetTable\n\t" <---- again
"L1: movzx eax, byte ptr [edi]\n\t"
" movzx eax, byte ptr [charsetTable+eax]\n\t"
" cmp al, 0\n\t"
" je L2\n\t"
" mov [edi],al\n\t"
" jmp L3\n\t"
"L2: xlat\n\t"
" mov [edi],al\n\t"
" inc edi\n\t"
" jmp L1\n\t"
"L3: popad\n\t");
It produces a non deterministic result in the plaintext variable.
How can i create a workaround, that every thread accesses his own plaintext variable? (If this is the problem...).
I tried modifying this code, to use extended assembly, but I failed every time. Probably due to the fact that all tutorials use ATT syntax.
I would really appreciate any help, as I'm stuck for several hours now :(
Edit: Running the program with 2 threads, and printing the content of plaintext right after the asm instruction, produces:
b
b
d
d
f
f
...
Edit2:
pthread_create(&thread[i], NULL, crack, (void *) &args[i]))
[...]
void *crack(void *arg) {
struct threadArgs *param = arg;
struct crypt_data crypt; // storage for reentrant version of crypt(3)
char *tmpHash = NULL;
size_t len = strlen(param->methodAndSalt);
size_t cipherlen = strlen(param->cipher);
crypt.initialized = 0;
for(int i = 0; i <= LIMIT; i++) {
// intel syntax
__asm__ ("pushad\n\t"
//mov edi, offset %0\n\t"
"mov edi, offset plaintext\n\t"
"mov ebx, offset charsetTable\n\t"
"L1: movzx eax, byte ptr [edi]\n\t"
" movzx eax, byte ptr [charsetTable+eax]\n\t"
" cmp al, 0\n\t"
" je L2\n\t"
" mov [edi],al\n\t"
" jmp L3\n\t"
"L2: xlat\n\t"
" mov [edi],al\n\t"
" inc edi\n\t"
" jmp L1\n\t"
"L3: popad\n\t");
tmpHash = crypt_r(plaintext, param->methodAndSalt, &crypt);
if(0 == memcmp(tmpHash+len, param->cipher, cipherlen)) {
printf("success: %s\n", plaintext);
break;
}
}
return 0;
}
Since you're already using pthreads, another option is making the variables that are modified by several threads into per-thread variables (threadspecific data). See pthread_getspecific OpenGroup manpage. The way this works is like:
In the main thread (before you create other threads), do:
static pthread_key_y tsd_key;
(void)pthread_key_create(&tsd_key); /* unlikely to fail; handle if you want */
and then within each thread, where you use the plaintext / charsetTable variables (or more such), do:
struct { char *plainText, char *charsetTable } *str =
pthread_getspecific(tsd_key);
if (str == NULL) {
str = malloc(2 * sizeof(char *));
str.plainText = malloc(size_of_plaintext);
str.charsetTable = malloc(size_of_charsetTable);
initialize(str.plainText); /* put the data for this thread in */
initialize(str.charsetTable); /* ditto */
pthread_setspecific(tsd_key, str);
}
char *plaintext = str.plainText;
char *charsetTable = str.charsetTable;
Or create / use several keys, one per such variable; in that case, you don't get the str container / double indirection / additional malloc.
Intel assembly syntax with gcc inline asm is, hm, not great; in particular, specifying input/output operands is not easy. I think to get that to use the pthread_getspecific mechanism, you'd change your code to do:
__asm__("pushad\n\t"
"push tsd_key\n\t" <---- threadspecific data key (arg to call)
"call pthread_getspecific\n\t" <---- gets "str" as per above
"add esp, 4\n\t" <---- get rid of the func argument
"mov edi, [eax]\n\t" <---- first ptr == "plainText"
"mov ebx, [eax + 4]\n\t" <---- 2nd ptr == "charsetTable"
...
That way, it becomes lock-free, at the expense of using more memory (one plaintext / charsetTable per thread), and the expense of an additional function call (to pthread_getspecific()). Also, if you do the above, make sure you free() each thread's specific data via pthread_atexit(), or else you'll leak.
If your function is fast to execute, then a lock is a much simpler solution because you don't need all the setup / cleanup overhead of threadspecific data; if the function is either slow or very frequently called, the lock would become a bottleneck though - in that case the memory / access overhead for TSD is justified. Your mileage may vary.
Protect this function with mutex outside of inline Assembly block.

Resources