两个本应兼容的函数指针类型被警告为不兼容。我违反了什么规则?
Two supposedly compatible function pointer types is being warned as incompatible. What rule am I breaking?
我有一组函数用于对大整数执行无符号模乘法。出于某种原因,当我在乘法中使用我的通用余数函数时,编译器(我使用带有 -Wall -Wextra
警告标志的 Clang)给出了不兼容的指针警告。
Header:
typedef struct {
uint32_t c;
uint32_t v[];
} vlong_t; // generic incomplete type.
vlong_t *vlong_remv_inplace(vlong_t *rem, const vlong_t *b);
typedef void *(*vlong_modfunc_t)(
vlong_t *restrict v,
void *restrict ctx);
vlong_t *vlong_mulv(
vlong_t *restrict out,
const vlong_t *a,
const vlong_t *b,
vlong_modfunc_t modfunc,
void *restrict mod_ctx);
给出警告的测试代码部分:
vlong_mulv(x, a, b, vlong_remv_inplace, b);
我稍微简化了代码以创建一个最小的工作示例,我的编码风格有不同的变量命名约定。
警告如下:
vlong-test.c:85:20: warning: incompatible pointer types passing 'vlong_t *(vlong_t *, const vlong_t *)' to parameter of type 'vlong_modfunc_t'
(aka 'void *(*)(vlong_t *restrict, void *restrict)') [-Wincompatible-pointer-types]
vlong_mulv(x, a, b, vlong_remv_inplace, b);
^~~~~~~~~~~~~~~~~~
我违反了什么规则?
警告是正确的,我使用了不同的 return 和参数类型。
虽然大多数遵循 ILP32
、LP64
或 IL32LLP64
的 C 调用约定要求所有指针都像 size_t
一样传递给被调用者,但标准并不排除可能的“lunati-c”实现,将指向不同类型的指针传递给可能不同的寄存器集。这与所有对象指针都可以无损地转换为 void *
并返回的事实无关。
C 标准工作草案 (n2573) 是这样说的:
6.3.2.3。 §8
A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
函数vlong_remv_inplace必须与类型vlong_modfunc_t具有相同的签名所以在vlong_remv_inplace 你需要把第二个参数的类型和结果替换成空指针:
void *vlong_remv_inplace(vlong_t *rem, void *b);
另一种方法是更改类型的签名 vlong_modfunc_t 以匹配函数的签名 vlong_remv_inplace.
vlong_t *vlong_remv_inplace(vlong_t *rem, const vlong_t *b);
typedef void *(*vlong_modfunc_t)(
vlong_t *restrict v,
void *restrict ctx);
vlong_t *vlong_mulv(
vlong_t *restrict out,
const vlong_t *a,
const vlong_t *b,
vlong_modfunc_t modfunc,
void *restrict mod_ctx);
函数 vlong_remv_implace
接受一个指向 vlong_t
的指针和一个指向 const vlong_t
的指针,而 vlong_modfunc_t
类型描述了一个指向接受受限制的函数的指针指向 vlong_t
的指针和指向非 const
vlong_t
的受限指针。 const
ness 应该匹配(并且可能还有指针参数的 restrict
ness,这也是不同的)以匹配指针类型。
我有一组函数用于对大整数执行无符号模乘法。出于某种原因,当我在乘法中使用我的通用余数函数时,编译器(我使用带有 -Wall -Wextra
警告标志的 Clang)给出了不兼容的指针警告。
Header:
typedef struct {
uint32_t c;
uint32_t v[];
} vlong_t; // generic incomplete type.
vlong_t *vlong_remv_inplace(vlong_t *rem, const vlong_t *b);
typedef void *(*vlong_modfunc_t)(
vlong_t *restrict v,
void *restrict ctx);
vlong_t *vlong_mulv(
vlong_t *restrict out,
const vlong_t *a,
const vlong_t *b,
vlong_modfunc_t modfunc,
void *restrict mod_ctx);
给出警告的测试代码部分:
vlong_mulv(x, a, b, vlong_remv_inplace, b);
我稍微简化了代码以创建一个最小的工作示例,我的编码风格有不同的变量命名约定。
警告如下:
vlong-test.c:85:20: warning: incompatible pointer types passing 'vlong_t *(vlong_t *, const vlong_t *)' to parameter of type 'vlong_modfunc_t'
(aka 'void *(*)(vlong_t *restrict, void *restrict)') [-Wincompatible-pointer-types]
vlong_mulv(x, a, b, vlong_remv_inplace, b);
^~~~~~~~~~~~~~~~~~
我违反了什么规则?
警告是正确的,我使用了不同的 return 和参数类型。
虽然大多数遵循 ILP32
、LP64
或 IL32LLP64
的 C 调用约定要求所有指针都像 size_t
一样传递给被调用者,但标准并不排除可能的“lunati-c”实现,将指向不同类型的指针传递给可能不同的寄存器集。这与所有对象指针都可以无损地转换为 void *
并返回的事实无关。
C 标准工作草案 (n2573) 是这样说的:
6.3.2.3。 §8
A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
函数vlong_remv_inplace必须与类型vlong_modfunc_t具有相同的签名所以在vlong_remv_inplace 你需要把第二个参数的类型和结果替换成空指针:
void *vlong_remv_inplace(vlong_t *rem, void *b);
另一种方法是更改类型的签名 vlong_modfunc_t 以匹配函数的签名 vlong_remv_inplace.
vlong_t *vlong_remv_inplace(vlong_t *rem, const vlong_t *b);
typedef void *(*vlong_modfunc_t)(
vlong_t *restrict v,
void *restrict ctx);
vlong_t *vlong_mulv(
vlong_t *restrict out,
const vlong_t *a,
const vlong_t *b,
vlong_modfunc_t modfunc,
void *restrict mod_ctx);
函数 vlong_remv_implace
接受一个指向 vlong_t
的指针和一个指向 const vlong_t
的指针,而 vlong_modfunc_t
类型描述了一个指向接受受限制的函数的指针指向 vlong_t
的指针和指向非 const
vlong_t
的受限指针。 const
ness 应该匹配(并且可能还有指针参数的 restrict
ness,这也是不同的)以匹配指针类型。