我试图使用的标准图书馆 qsort 排序的一系列广泛的角色:

wchar_t a = L'a';
wchar_t a1 = L'ä';
wchar_t b = L'z';
wchar_t chararray[] = {b, a, a1};  
length = wcslen(chararray);

qsort(chararray, length, sizeof(wchar_t), wcscoll);

现在我想的职能参与有这些原型:

int wcscoll(const wchar_t *ws1, const wchar_t *ws2);
void qsort(void *base, size_t num, size_t size, int (*comp_func)(const void *, const void *))

结果都完全按预期,但是为什么我会得到警告编译器 "passing argument 4 of ‘qsort’ from incompatible pointer type"?我怎么能投 wcscoll 适合的原型?

警告就离开如果我定义,并通过在一个单独的比较功能:

int widecharcomp(const void *arg1, const void *arg2)
{
    return wcscoll(arg1, arg2);
}

...但这个看起来像它应该有错误处理当的参数的类型不 wchar_t *.

有帮助吗?

解决方案

有两个问题:您混杂了 wchar_twchar_t*, ,您已经试图通过 wchar_t* 作为一个 void*.

首先,你告诉 qsort 分类一系列 wchar_t. 。但 wcscoll 不比较 wchar_t, ,它比较具有类型的宽字符串 wchar_t*. 。您的比较似乎起作用的事实是由于您的测试数据所致,这在两个解释下都恰好效果很好。

如果您想对字符进行排序,则需要调用适当的功能(我不太了解宽字符API足以告诉您哪一个)。如果您想对字符串进行排序,则需要分配一系列字符串(类型 wchar_t *).

此外,即使您有一系列 wchar_t*, ,您无法及时通过 wcscoll 作为争论 qsort. 。问题是不能保证 wchar_t*void* 具有相同的表示形式。一些机器的单词指针与字节指针不同。在这样的机器上 qsort 会将字节指针传递到阵列的元素 wcscoll, ,这是行不通的,因为 wcscoll 期望字节指针。解决方案是编写一个琐碎的包装函数,如有必要,该功能执行转换。通常需要一个琐碎的包装器 qsort.

其他提示

你已经做了相当多的正确方法。 海湾合作委员会的文档 strcollwcscoll 给出一个示例,类似于为这是正确的方式来使用 strcollwcscollqsort.

 /* This is the comparison function used with qsort. */

 int
 compare_elements (char **p1, char **p2)
 {
   return strcoll (*p1, *p2);
 }

 /* This is the entry point---the function to sort
    strings using the locale's collating sequence. */

 void
 sort_strings (char **array, int nstrings)
 {
   /* Sort temp_array by comparing the strings. */
   qsort (array, nstrings,
          sizeof (char *), compare_elements);
 }

这个例子实际上不会提出的警告,你想要摆脱的,但同样可以得到解决,通过改变 char**const void* 在参数 compare_elements, ,然后明确地铸造 const char**.

你就在观察这类不安全的,但类型的安全是不完全一C的强点。C没有任何东西喜欢泛或模板,因此唯一的方法时,qsort可以工作上的任意一种类型是对其比较能接受 void*s.它是由程序员,以确保比较功能不是用在上下文中这可以通过论点是没有预期的类型。

这就是说, 有一个错误代码.什么比较功能接收的不是要素进行比较,而是 指针的要素进行比较.因此,如果元素弦,这意味着指针指针。所以当你写的

return wcscoll(arg1, arg2);

你实际上是路过 wscoll 一个 wchar_t** 当预计一个 wchar_t*.正确的方式做到这一点,同时抑制警告,将是:

int widecharcomp(const void *arg1, const void *arg2)
{
    return wcscoll(*(const w_char_t**)arg1, *(const w_char_t**)arg2);
}

作为丑陋的,因为这是。

编辑:

只是采取了另一个顶点,你的代码。你的错误是真的有两个在这里。你试图使用 wcscoll 排序符。这是一个功能是排序 字符串 (这在C是指向nul-终止序列的字符)。上面写假设你是想排序串。如果你想要的排序符的,然后 wcscoll 是不适当的功能使用的,但上面的一切关于 qsort 仍然适用。

您已经对解决方案进行了编码(但是,请参阅此末尾的其他答案和编辑,并选择您使用的比较函数以及将数据传递给 qsort()).

您可以通过施放您传递的功能指针来删除包装器功能 qsort() 从可维护性的角度来看,对于适当的类型,我认为使用包装器是更好的解决方案。如果您真的想避免包装器功能(也许您正在遇到可衡量的完美问题),那么您可以这样铸造:

qsort(chararray, length, sizeof(wchar_t), (int(*)(const void*,const void*))wcscoll);

或者,使用Typedef进行比较函数类型,可以说它更具可读性:

typedef
int (*comp_func_t)(const void *, const void *);

/* ... */
qsort(chararray, length, sizeof(wchar_t), (comp_func_t) wcscoll);

不幸的是,直c qsort() 不能像typesafe一样,因此它不能具有“当参数不为wchar_t类型时,要处理错误”。您,程序员,负责确保您将正确的数据,大小和比较功能传递给 qsort().


编辑:

为了解决其他答案中有关所传递类型的一些问题,这是一个例程,可用于使用当前语言环境的整理序列对WCHAR_T进行分类。图书馆可能有更好的东西,但目前我还不知道:

int wchar_t_coll( const void* p1, const void* p2)
{
    wchar_t s1[2] = {0};
    wchar_t s2[2] = {0};

    s1[0] = * (wchar_t*)p1;
    s2[0] = * (wchar_t*)p2;

    return wcscoll( s1, s2);
}

另请注意, chararray 你经过 wcslen() 无法正确终止 - 您需要一个 0 在初始化器的末尾:

wchar_t chararray[] = {b, a, a1, 0};  

您无法投射到其他类型的功能指针,您当前的解决方案是很好的

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top