![](/img/trans.png)
[英]C : why is that cast of void function to "pointer to function returning pointer to pointer to void" possible
[英]Why accept void* pointer as a function argument when it is always cast to the same type in the function body in C?
我看到一些 C 函數將void*
指針作為參數,然后在 function 的主體中,指針的唯一用法是在每次使用時將其轉換為相同的類型(在我的例子中為unsigned char*
) .
我知道這是一個合法的操作,我的問題是為什么不只接受一個指向unsigned char
的指針而不是接受一個void*
並每次都轉換它? 這樣做是否有一些性能改進或一些限制?
如果你想要一個代碼示例,請查看參數datum
處的profileImage方法(第 933 行)(演員表位於第 989 行):
MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
const void *datum,const size_t length,ExceptionInfo *exception)
{
#define ProfileImageTag "Profile/Image"
#ifndef TYPE_XYZ_8
#define TYPE_XYZ_8 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(1))
#endif
#define ThrowProfileException(severity,tag,context) \
{ \
if (profile != (StringInfo *) NULL) \
profile=DestroyStringInfo(profile); \
if (cms_context != (cmsContext) NULL) \
cmsDeleteContext(cms_context); \
if (source_info.profile != (cmsHPROFILE) NULL) \
(void) cmsCloseProfile(source_info.profile); \
if (target_info.profile != (cmsHPROFILE) NULL) \
(void) cmsCloseProfile(target_info.profile); \
ThrowBinaryException(severity,tag,context); \
}
MagickBooleanType
status;
StringInfo
*profile;
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(name != (const char *) NULL);
if (IsEventLogging() != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
if ((datum == (const void *) NULL) || (length == 0))
{
char
*next;
/*
Delete image profile(s).
*/
ResetImageProfileIterator(image);
for (next=GetNextImageProfile(image); next != (const char *) NULL; )
{
if (IsOptionMember(next,name) != MagickFalse)
{
(void) DeleteImageProfile(image,next);
ResetImageProfileIterator(image);
}
next=GetNextImageProfile(image);
}
return(MagickTrue);
}
/*
Add a ICC, IPTC, or generic profile to the image.
*/
status=MagickTrue;
profile=AcquireStringInfo((size_t) length);
SetStringInfoDatum(profile,(unsigned char *) datum);
if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
status=SetImageProfile(image,name,profile,exception);
else
{
const StringInfo
*icc_profile;
icc_profile=GetImageProfile(image,"icc");
if ((icc_profile != (const StringInfo *) NULL) &&
(CompareStringInfo(icc_profile,profile) == 0))
{
const char
*value;
value=GetImageProperty(image,"exif:ColorSpace",exception);
(void) value;
if (LocaleCompare(value,"1") != 0)
(void) SetsRGBImageProfile(image,exception);
value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
if (LocaleCompare(value,"R98.") != 0)
(void) SetsRGBImageProfile(image,exception);
icc_profile=GetImageProfile(image,"icc");
}
if ((icc_profile != (const StringInfo *) NULL) &&
(CompareStringInfo(icc_profile,profile) == 0))
{
profile=DestroyStringInfo(profile);
return(MagickTrue);
}
#if !defined(MAGICKCORE_LCMS_DELEGATE)
(void) ThrowMagickException(exception,GetMagickModule(),
MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
"'%s' (LCMS)",image->filename);
#else
{
cmsContext
cms_context;
CMSExceptionInfo
cms_exception;
LCMSInfo
source_info,
target_info;
/*
Transform pixel colors as defined by the color profiles.
*/
cms_exception.image=image;
cms_exception.exception=exception;
cms_context=cmsCreateContext(NULL,&cms_exception);
if (cms_context == (cmsContext) NULL)
{
profile=DestroyStringInfo(profile);
ThrowBinaryException(ResourceLimitError,
"ColorspaceColorProfileMismatch",name);
}
cmsSetLogErrorHandlerTHR(cms_context,CMSExceptionHandler);
source_info.profile=cmsOpenProfileFromMemTHR(cms_context,
GetStringInfoDatum(profile),(cmsUInt32Number)
GetStringInfoLength(profile));
if (source_info.profile == (cmsHPROFILE) NULL)
{
profile=DestroyStringInfo(profile);
cmsDeleteContext(cms_context);
ThrowBinaryException(ResourceLimitError,
"ColorspaceColorProfileMismatch",name);
}
if ((cmsGetDeviceClass(source_info.profile) != cmsSigLinkClass) &&
(icc_profile == (StringInfo *) NULL))
status=SetImageProfile(image,name,profile,exception);
else
{
CacheView
*image_view;
cmsColorSpaceSignature
signature;
cmsHTRANSFORM
*magick_restrict transform;
cmsUInt32Number
flags;
MagickBooleanType
highres;
MagickOffsetType
progress;
ssize_t
y;
target_info.profile=(cmsHPROFILE) NULL;
if (icc_profile != (StringInfo *) NULL)
{
target_info.profile=source_info.profile;
source_info.profile=cmsOpenProfileFromMemTHR(cms_context,
GetStringInfoDatum(icc_profile),(cmsUInt32Number)
GetStringInfoLength(icc_profile));
if (source_info.profile == (cmsHPROFILE) NULL)
ThrowProfileException(ResourceLimitError,
"ColorspaceColorProfileMismatch",name);
}
highres=MagickTrue;
#if !defined(MAGICKCORE_HDRI_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH > 16)
{
const char
*artifact;
artifact=GetImageArtifact(image,"profile:highres-transform");
if (IsStringFalse(artifact) != MagickFalse)
highres=MagickFalse;
}
#endif
SetLCMSInfoScale(&source_info,1.0);
SetLCMSInfoTranslate(&source_info,0.0);
source_info.colorspace=sRGBColorspace;
source_info.channels=3;
switch (cmsGetColorSpace(source_info.profile))
{
case cmsSigCmykData:
{
source_info.colorspace=CMYKColorspace;
source_info.channels=4;
if (highres != MagickFalse)
{
source_info.type=(cmsUInt32Number) TYPE_CMYK_DBL;
SetLCMSInfoScale(&source_info,100.0);
}
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
source_info.type=(cmsUInt32Number) TYPE_CMYK_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
source_info.type=(cmsUInt32Number) TYPE_CMYK_16;
#endif
break;
}
case cmsSigGrayData:
{
source_info.colorspace=GRAYColorspace;
source_info.channels=1;
if (highres != MagickFalse)
source_info.type=(cmsUInt32Number) TYPE_GRAY_DBL;
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
source_info.type=(cmsUInt32Number) TYPE_GRAY_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
source_info.type=(cmsUInt32Number) TYPE_GRAY_16;
#endif
break;
}
case cmsSigLabData:
{
source_info.colorspace=LabColorspace;
if (highres != MagickFalse)
{
source_info.type=(cmsUInt32Number) TYPE_Lab_DBL;
source_info.scale[0]=100.0;
source_info.scale[1]=255.0;
source_info.scale[2]=255.0;
source_info.translate[1]=(-0.5);
source_info.translate[2]=(-0.5);
}
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
source_info.type=(cmsUInt32Number) TYPE_Lab_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
source_info.type=(cmsUInt32Number) TYPE_Lab_16;
#endif
break;
}
case cmsSigRgbData:
{
source_info.colorspace=sRGBColorspace;
if (highres != MagickFalse)
source_info.type=(cmsUInt32Number) TYPE_RGB_DBL;
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
source_info.type=(cmsUInt32Number) TYPE_RGB_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
source_info.type=(cmsUInt32Number) TYPE_RGB_16;
#endif
break;
}
case cmsSigXYZData:
{
source_info.colorspace=XYZColorspace;
if (highres != MagickFalse)
source_info.type=(cmsUInt32Number) TYPE_XYZ_DBL;
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
source_info.type=(cmsUInt32Number) TYPE_XYZ_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
source_info.type=(cmsUInt32Number) TYPE_XYZ_16;
#endif
break;
}
default:
ThrowProfileException(ImageError,
"ColorspaceColorProfileMismatch",name);
}
signature=cmsGetPCS(source_info.profile);
if (target_info.profile != (cmsHPROFILE) NULL)
signature=cmsGetColorSpace(target_info.profile);
SetLCMSInfoScale(&target_info,1.0);
SetLCMSInfoTranslate(&target_info,0.0);
target_info.channels=3;
switch (signature)
{
case cmsSigCmykData:
{
target_info.colorspace=CMYKColorspace;
target_info.channels=4;
if (highres != MagickFalse)
{
target_info.type=(cmsUInt32Number) TYPE_CMYK_DBL;
SetLCMSInfoScale(&target_info,0.01);
}
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
target_info.type=(cmsUInt32Number) TYPE_CMYK_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
target_info.type=(cmsUInt32Number) TYPE_CMYK_16;
#endif
break;
}
case cmsSigGrayData:
{
target_info.colorspace=GRAYColorspace;
target_info.channels=1;
if (highres != MagickFalse)
target_info.type=(cmsUInt32Number) TYPE_GRAY_DBL;
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
target_info.type=(cmsUInt32Number) TYPE_GRAY_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
target_info.type=(cmsUInt32Number) TYPE_GRAY_16;
#endif
break;
}
case cmsSigLabData:
{
target_info.colorspace=LabColorspace;
if (highres != MagickFalse)
{
target_info.type=(cmsUInt32Number) TYPE_Lab_DBL;
target_info.scale[0]=0.01;
target_info.scale[1]=1/255.0;
target_info.scale[2]=1/255.0;
target_info.translate[1]=0.5;
target_info.translate[2]=0.5;
}
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
target_info.type=(cmsUInt32Number) TYPE_Lab_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
target_info.type=(cmsUInt32Number) TYPE_Lab_16;
#endif
break;
}
case cmsSigRgbData:
{
target_info.colorspace=sRGBColorspace;
if (highres != MagickFalse)
target_info.type=(cmsUInt32Number) TYPE_RGB_DBL;
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
target_info.type=(cmsUInt32Number) TYPE_RGB_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
target_info.type=(cmsUInt32Number) TYPE_RGB_16;
#endif
break;
}
case cmsSigXYZData:
{
target_info.colorspace=XYZColorspace;
if (highres != MagickFalse)
target_info.type=(cmsUInt32Number) TYPE_XYZ_DBL;
#if (MAGICKCORE_QUANTUM_DEPTH == 8)
else
target_info.type=(cmsUInt32Number) TYPE_XYZ_8;
#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
else
source_info.type=(cmsUInt32Number) TYPE_XYZ_16;
#endif
break;
}
default:
ThrowProfileException(ImageError,
"ColorspaceColorProfileMismatch",name);
}
switch (image->rendering_intent)
{
case AbsoluteIntent:
{
target_info.intent=INTENT_ABSOLUTE_COLORIMETRIC;
break;
}
case PerceptualIntent:
{
target_info.intent=INTENT_PERCEPTUAL;
break;
}
case RelativeIntent:
{
target_info.intent=INTENT_RELATIVE_COLORIMETRIC;
break;
}
case SaturationIntent:
{
target_info.intent=INTENT_SATURATION;
break;
}
default:
{
target_info.intent=INTENT_PERCEPTUAL;
break;
}
}
flags=cmsFLAGS_HIGHRESPRECALC;
#if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
if (image->black_point_compensation != MagickFalse)
flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
#endif
transform=AcquireTransformTLS(&source_info,&target_info,flags,
cms_context);
if (transform == (cmsHTRANSFORM *) NULL)
ThrowProfileException(ImageError,"UnableToCreateColorTransform",
name);
/*
Transform image as dictated by the source & target image profiles.
*/
source_info.pixels=AcquirePixelTLS(image->columns,
source_info.channels,highres);
target_info.pixels=AcquirePixelTLS(image->columns,
target_info.channels,highres);
if ((source_info.pixels == (void **) NULL) ||
(target_info.pixels == (void **) NULL))
{
target_info.pixels=DestroyPixelTLS(target_info.pixels);
source_info.pixels=DestroyPixelTLS(source_info.pixels);
transform=DestroyTransformTLS(transform);
ThrowProfileException(ResourceLimitError,
"MemoryAllocationFailed",image->filename);
}
if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
{
target_info.pixels=DestroyPixelTLS(target_info.pixels);
source_info.pixels=DestroyPixelTLS(source_info.pixels);
transform=DestroyTransformTLS(transform);
if (source_info.profile != (cmsHPROFILE) NULL)
(void) cmsCloseProfile(source_info.profile);
if (target_info.profile != (cmsHPROFILE) NULL)
(void) cmsCloseProfile(target_info.profile);
return(MagickFalse);
}
if (target_info.colorspace == CMYKColorspace)
(void) SetImageColorspace(image,target_info.colorspace,exception);
progress=0;
image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp parallel for schedule(static) shared(status) \
magick_number_threads(image,image,image->rows,1)
#endif
for (y=0; y < (ssize_t) image->rows; y++)
{
const int
id = GetOpenMPThreadId();
MagickBooleanType
sync;
Quantum
*magick_restrict q;
if (status == MagickFalse)
continue;
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
exception);
if (q == (Quantum *) NULL)
{
status=MagickFalse;
continue;
}
if (highres != MagickFalse)
TransformDoublePixels(id,image,&source_info,&target_info,
transform,q);
else
TransformQuantumPixels(id,image,&source_info,&target_info,
transform,q);
sync=SyncCacheViewAuthenticPixels(image_view,exception);
if (sync == MagickFalse)
status=MagickFalse;
if (image->progress_monitor != (MagickProgressMonitor) NULL)
{
MagickBooleanType
proceed;
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp atomic
#endif
progress++;
proceed=SetImageProgress(image,ProfileImageTag,progress,
image->rows);
if (proceed == MagickFalse)
status=MagickFalse;
}
}
image_view=DestroyCacheView(image_view);
(void) SetImageColorspace(image,target_info.colorspace,exception);
switch (signature)
{
case cmsSigRgbData:
{
image->type=image->alpha_trait == UndefinedPixelTrait ?
TrueColorType : TrueColorAlphaType;
break;
}
case cmsSigCmykData:
{
image->type=image->alpha_trait == UndefinedPixelTrait ?
ColorSeparationType : ColorSeparationAlphaType;
break;
}
case cmsSigGrayData:
{
image->type=image->alpha_trait == UndefinedPixelTrait ?
GrayscaleType : GrayscaleAlphaType;
break;
}
default:
break;
}
target_info.pixels=DestroyPixelTLS(target_info.pixels);
source_info.pixels=DestroyPixelTLS(source_info.pixels);
transform=DestroyTransformTLS(transform);
if ((status != MagickFalse) &&
(cmsGetDeviceClass(source_info.profile) != cmsSigLinkClass))
status=SetImageProfile(image,name,profile,exception);
if (target_info.profile != (cmsHPROFILE) NULL)
(void) cmsCloseProfile(target_info.profile);
}
(void) cmsCloseProfile(source_info.profile);
cmsDeleteContext(cms_context);
}
#endif
}
profile=DestroyStringInfo(profile);
return(status);
}
我認為他們只是寫了糟糕的代碼(在這個特殊情況下,我只想說;而且:我們有時都會寫糟糕的代碼——我們邊走邊學/成長)。 如果他們想要那種類型,他們應該使用unsigned char
unsigned char*
,如果他們希望參數是可選的,可以偶爾傳入NULL
來代替值,那么他們應該使用 unsigned char*。 void*
不鼓勵用於“通用編程”目的,除非確實有必要,因為它會阻止編譯器進行嚴格的類型檢查,並可能導致更多錯誤。 請注意,在 pthread 庫和我下面的示例中,它確實是必要的。 這些都是void*
的好用法。 正確使用和使用得當以及應該使用的時候都是好的。
void*
類型的“通用函數”來接受和返回任何類型 void*
使用得當,與速度、效率無關。 相反,它與多功能性有關。
接受void*
的函數是通用函數(我不知道這是“官方”還是“公認術語”;我只是這么稱呼它們)。 例如,它們可以讓您傳遞函數或注冊可以做任何您喜歡的事情的函數。
這是一個簡單的例子。 想象一下,一個通用庫允許您注冊回調 function,它將在稍后調用:
// Define `func_t` as a function ptr whose signature looks like this:
// `void* func(void*);`
typedef void* (*func_t)(void*);
// a generic library function (not written by the user of the library)
void* register_callback(func_t user_func, void* args_to_user_func)
{
// have this function call the function passed to it, and return what it
// returns, for demo purposes
return user_func(args_to_user_func);
}
現在,這個通用庫的用戶可以傳入他們想要的任何 function 接受並返回他們想要的任何類型。 前任:
// EXAMPLE 1
// user function 1
void* print_int(void* int_ptr)
{
int val = *(int*)int_ptr; // extract the integer from the passed-in arg
printf("%i\n", val);
return NULL;
}
int int_to_print = 7;
register_callback(print_int, &int_to_print);
// EXAMPLE 2
typedef struct my_struct_s
{
int i;
float f;
bool b;
} my_struct_t;
// user function 2
void* print_struct(void* my_struct_ptr_in)
{
my_struct_t *my_struct_ptr = (my_struct_t*)my_struct_ptr_in;
printf("%i, %f, %s\n",
my_struct_ptr->i
my_struct_ptr->f,
my_struct_ptr->b ? "true" : "false");
return NULL;
}
my_struct_t my_struct =
{
.i = 7,
.f = 17.1308;
.b = true;
};
register_callback(print_struct, &my_struct);
看到這里的美了嗎? register_callback()
現在是一種通用類型 function,它可以接受回調 function,它可以執行任何操作並打印任何內容並接收任何類型的變量。 它的可能性是無限的。
pthread 庫需要這種類型的“通用函數”行為來運行線程。 您必須傳入一個您希望線程運行的 function,以及一個包含您需要 function 接收的任何 arguments 的void*
。 要傳遞“多個”args,請通過 ptr 將它們傳遞給包含多個 args 的結構,正如我在上面演示的那樣。
要在 C++ 中執行此操作,您可以執行與上面相同的代碼,或者您可以改用此模板巫術:我的回答:How to use variadic templates (parameter packs) in C++ to pass a variadic list of arguments to a sub-function
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.