英文:
Why is a cast of uintptr_t used here?
问题
以下是您要翻译的代码部分:
struct arguments {
uint32_t threads;
uint32_t size;
};
void *run_v1(void *arg) {
uint32_t thread = (uintptr_t) arg;
for (uint32_t j = 0; j < arguments.size; ++j) {
size_t global_index = get_global_index(thread, j);
char *string = get_string(global_index);
hash_table_v1_add_entry(hash_table_v1, string, global_index);
}
return NULL;
}
...
int main () {
...
for (uintptr_t i = 0; i < arguments.threads; ++i) {
int err = pthread_create(&threads[i], NULL, run_v1, (void*) i);
if (err != 0) {
printf("pthread_create returned %d\n", err);
return err;
}
}
...
}
关于您的问题,为什么需要将参数转换为uintptr_t
类型而不是直接传递uint32_t
并将其强制转换回自身,原因是pthread_create
函数的第四个参数需要是void*
类型。uintptr_t
是一个无符号整数类型,足够大,可以容纳指针,因此可以安全地将uint32_t
转换为uintptr_t
,然后将其传递给pthread_create
。这样做是为了符合pthread_create
函数的接口要求,以避免类型不匹配的问题,不会导致未定义行为。
英文:
Here it is, in the context of pthread.h
and stdint.h
:
struct arguments {
uint32_t threads;
uint32_t size;
};
void *run_v1(void *arg) {
uint32_t thread = (uintptr_t) arg;
for (uint32_t j = 0; j < arguments.size; ++j) {
size_t global_index = get_global_index(thread, j);
char *string = get_string(global_index);
hash_table_v1_add_entry(hash_table_v1, string, global_index);
}
return NULL;
}
...
int main () {
...
for (uintptr_t i = 0; i < arguments.threads; ++i) {
int err = pthread_create(&threads[i], NULL, run_v1, (void*) i);
if (err != 0) {
printf("pthread_create returned %d\n", err);
return err;
}
}
...
}
This is my professor's code, I read the specification here:
> The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to a pointer to void, and the result will compare equal to the original pointer: uintptr_t
Why is the cast to this type necessary, rather than passing in a uint32_t
and casting to itself? Is this undefined behavior?
答案1
得分: 1
以下是翻译好的内容:
强制转换保证指针以可逆的方式转换为无符号整数类型。
如果此类型大于uint32_t
,编译器将引发警告。
直接强制转换为uint32_t
可能会隐藏转换不可逆的事实。(尽管,老实说,我无法想象出一种导致这种情况的实现方式。)
英文:
The cast guarantees that the pointer be converted to an unsigned integer type in a reversible way.
In case this type is larger than a uint32_t
, a compiler warning will be raised.
A direct cast to uint32_t
might hide the fact that the conversion is not reversible. (Though, honestly, I cannot think of a implementation causing that.)
答案2
得分: 1
我理解了,以下是你要求的代码部分的翻译:
为什么需要将其转换为此类型,
这是不必要的。
而不是传递一个 uint32_t 并将其强制转换为自身?
这是我会做的。
这是未定义行为吗?
可能。但它肯定依赖于实现定义的行为。
在这里需要考虑通用原则和特定问题的原则。
最相关的通用原则 是你引用的 uintptr_t
的定义。它告诉你 uintptr_t
可以表示与每个独特、有效的 void *
值相对应的独特值,因此你可以确信将 void *
转换为 uintptr_t
类型不会导致信息丢失。因此,通常情况下,如果你想将一个对象指针表示为整数,uintptr_t
就是要选择的整数类型。
人们普遍认为 uintptr_t
必须与 void *
的大小相同,但尽管通常情况下如此,语言规范并未要求如此。由于 uintptr_t
只需为有效指针值提供不同的表示,并且由于不同的 void *
位模式不必表示不同的地址,因此 uintptr_t
可能比 void *
更小。另一方面,如果它比 void *
大,它也可以很好地完成其任务。
此外,语言规范要求你可以通过类型 uintptr_t
对指针进行往返转换,但并不要求你可以通过指针对任何类型的整数进行往返转换。大多数整数到指针的转换的结果是实现定义的。也就是说,鉴于这个...
uintptr_t x;
// .. 为 x 赋值 ...
... 语言规范允许这段代码打印出 "unequal":
if (x == (uintptr_t)(void *) x) {
puts("equal");
} else {
puts("unequal");
}
但在这个具体的情况中,
-
要传达的值的上限从类型为
uint32_t
的对象中读取,因此所有要传达的值都可以由该类型表示;以及 -
程序假设 C 实现中整数 -> 指针 -> 整数的过程会为所有要传达的整数值复制原始值。
在这些情况下,语言语义没有理由优先选择 uintptr_t
而不是涉及的整数类型。也就是说,如果所提供的代码正确运行,那么一个版本中用 uint32_t
替代 uinptr_t
也必须正确运行。而我认为后者更清晰、更简洁。
英文:
> Why is the cast to this type necessary,
It is not.
> rather than passing in a uint32_t and casting to itself?
That's what I would do.
> Is this undefined behavior?
Maybe. But it definitely relies on implementation-defined behavior.
There are both general principles and problem-specific ones to consider here.
The most relevant general principle is the definition of uintptr_t
, which you quoted. It tells you that uintptr_t
can represent a distinct value corresponding to each distinct, valid void *
value, so you can be confident that converting a void *
to type uintptr_t
will not produce a loss of fidelity. In general, then, if you want to represent an object pointer as an integer, uintptr_t
is the integer type to choose.
It is relatively common to conclude that uintptr_t
must be the same size as a void *
, but although that's often true, the language spec places no such requirement. Since uintptr_t
needs only to provide distinct representations for valid pointer values, and also because distinct void *
bit patterns don't have to represent distinct addresses, uintptr_t
could conceivably be smaller than void *
. On the other hand, it can fulfill its role just fine if it is larger than void *
.
Moreover, the language spec requires that you can round-trip pointers through type uintptr_t
, but it does not require that you can round-trip any variety of integer through a pointer. The results of most integer-to-pointer conversions are implementation defined. That is, given this ...
uintptr_t x;
// .. assign a value to x ...
... the language spec allows this to print "unequal":
if (x == (uintptr_t)(void *) x) {
puts("equal");
} else {
puts("unequal");
}
But in this specific case,
-
the upper bound on the values to be conveyed is read from an object of type
uint32_t
, and therefore all values to be conveyed are representable by that type; and -
the program is assuming a C implementation in which the integer --> pointer --> integer transit reproduces the original value for all the integer values to be conveyed.
Under these circumstances, language semantics present no reason to prefer uintptr_t
over uint32_t
as the integer type involved. That is, if the code presented works correctly, then a version in which uinptr_t
is replaced replaced with uint32_t
must also work correctly. And I find the latter alternative cleaner and clearer.
答案3
得分: 0
Here is the translation of the provided text:
> 为什么需要将其强制转换为这种类型,而不是转换为 uint32_t
?
这不是必需的,但如果 uint32_t
比 uintptr_t
小,你可能会收到一个关于“从指针到不同大小的整数的转换”的警告。另一方面,uintptr_t
被定义为能够将指针值存储为整数。
当进行到 uintptr_t
的强制转换时,您可能仍然会收到一个关于“隐式转换会丢失整数精度”的警告,所以如果您最初存储在 void*
中的内容实际上是 uint32_t
,则需要添加一个强制转换以避免潜在的警告:
uint32_t thread = (uint32_t)(uintptr_t)arg;
然而,我建议通过指针发送值,然后您就不需要任何显式的强制转换:
void *run(void *arg) {
uint32_t *ptr = arg;
uint32_t thread = *ptr;
...
return NULL;
}
uint32_t value;
pthread_create(..., &value);
一个更详细的示例,演示如何使用传递指针,如果您的线程需要比单个 uint32_t
更多的数据,可以看起来像这样:
#include <pthread.h>
#include <stdint.h>
#include <stddef.h>
#define SIZE(x) (sizeof (x) / sizeof *(x))
typedef struct {
uint32_t value;
// 其他线程需要的数据可以添加在这里
} thread_data;
void *run(void *arg) {
thread_data *data = arg;
// 在这里处理数据
return NULL;
}
int main() {
pthread_t th[10];
thread_data data[SIZE(th)];
for(int i = 0; i < SIZE(th); ++i) {
// 用要处理的值填充 data[i]
pthread_create(&th[i], NULL, run, &data[i]);
}
// ... 加入等等 ...
}
英文:
> Why is the cast to this type necessary, rather than a cast to uint32_t
?
It is not, but if uint32_t
is smaller than uintptr_t
you may get a warning about "cast from pointer to integer of different size". uintptr_t
on the other hand is defined to be able to store pointer values as integers.
When the cast to uintptr_t
is done you may still get a warning about "implicit conversion loses integer precision", so if what you've stored in the void*
was actually an uint32_t
to start with, add a cast to not get that potential warning:
uint32_t thread = (uint32_t)(uintptr_t)arg;
However, I suggest sending in the value via a pointer and then you wouldn't need any explicit casts:
void *run(void *arg) {
uint32_t *ptr = arg;
uint32_t thread = *ptr;
...
return NULL;
}
uint32_t value;
pthread_create(..., &value);
A more elaborate example of making use of passing a pointer which is easy to extend if your thread needs more data than a single uint32_t
could look like this:
#include <pthread.h>
#include <stdint.h>
#include <stddef.h>
#define SIZE(x) (sizeof (x) / sizeof *(x))
typedef struct {
uint32_t value;
// other data that the thread needs can be added here
} thread_data;
void *run(void *arg) {
thread_data *data = arg;
// work with data here
return NULL;
}
int main() {
pthread_t th[10];
thread_data data[SIZE(th)];
for(int i = 0; i < SIZE(th); ++i) {
// fill data[i] with values to work with
pthread_create(&th[i], NULL, run, &data[i]);
}
// ... join etc ...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论