I saw some C functions take a void*
pointer as an argument, then in the body of the function, the only usage of the pointer is done after casting it to the same type each time it is used ( unsigned char*
in my case).
I know this is a legal operation, my question is why not just accept a pointer to unsigned char
instead of accepting a void*
and casting it each time? Is there some performance improvement or some limitation on doing this?
If you want a code example, have a look at profileImage method (line 933) at the parameter datum
(and the cast is at line 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);
}
I think they just wrote lousy code (in this one particular case is all I'm saying; and: we all write lousy code sometimes--we learn as we go/grow). They should have used unsigned char
if they want that type, and maybe unsigned char*
if they want the parameter to be optional by passing in a NULL
in place of a value occasionally. void*
is discouraged for "generic programming" purposes unless it really is necessary, as it prevents the compiler from doing strict type checking, and can lead to more bugs. Note that in the pthread library and in my examples below, it really is necessary . Those are good uses of void*
. It is good when used right and used well and when used when it should be.
void*
type "universal functions" to accept and return any typeWhen void*
is used properly, it has nothing to do with speed or efficiency. Rather, it has to do with versatility .
Functions which accept void*
are universal functions (I don't know if that's an "official" or "accepted term"; I'm just calling them that). They can allow you to pass functions or register functions which can do anything you like, for instance.
Here's a simple example. Imagine a generic library allows you to register your callback function it will call later:
// 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);
}
Now, the user of this generic library can pass in whatever function they want that accepts and returns any type they want. Ex:
// 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);
See the beauty of this? register_callback()
is now a type of universal function which can accept a callback function which can do anything and print anything and receive any type of variables. Its possibilities are unlimited.
The pthread library requires this type of "universal function" behavior for running threads. You have to pass in a function you want the thread to run, and a void*
containing whatever arguments you need that function to receive. To pass "multiple" args, pass them in via a ptr to a struct containing multiple args, as I demonstrated above.
To do this in C++ , you can do the same code as above, or you can do this template voodoo instead: my answer: How to use variadic templates (parameter packs) in C++ to pass a variadic list of arguments to a sub-function
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.