简体   繁体   English

为什么接受 void* 指针作为 function 参数,因为它总是在 C 的 function 主体中转换为相同类型?

[英]Why accept void* pointer as a function argument when it is always cast to the same type in the function body in C?

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).我看到一些 C 函数将void*指针作为参数,然后在 function 的主体中,指针的唯一用法是在每次使用时将其转换为相同的类型(在我的例子中为unsigned char* ) .

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?我知道这是一个合法的操作,我的问题是为什么不只接受一个指向unsigned char的指针而不是接受一个void*并每次都转换它? 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):如果你想要一个代码示例,请查看参数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);
 }

In the code in question...在有问题的代码中......

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.如果他们想要那种类型,他们应该使用unsigned char unsigned char* ,如果他们希望参数是可选的,可以偶尔传入NULL来代替值,那么他们应该使用 unsigned char*。 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. void*不鼓励用于“通用编程”目的,除非确实有必要,因为它会阻止编译器进行严格的类型检查,并可能导致更多错误。 Note that in the pthread library and in my examples below, it really is necessary .请注意,在 pthread 库和我下面的示例中,它确实是必要的 Those are good uses of void* .这些都是void*的好用法。 It is good when used right and used well and when used when it should be.正确使用和使用得当以及应该使用的时候都是好的。

How to use void* type "universal functions" to accept and return any type如何使用void*类型的“通用函数”来接受和返回任何类型

When void* is used properly, it has nothing to do with speed or efficiency. void*使用得当,与速度、效率无关。 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).接受void*的函数是通用函数(我不知道这是“官方”还是“公认术语”;我只是这么称呼它们)。 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:想象一下,一个通用库允许您注册回调 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);
}

Now, the user of this generic library can pass in whatever function they want that accepts and returns any type they want.现在,这个通用库的用户可以传入他们想要的任何 function 接受并返回他们想要的任何类型。 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. register_callback()现在是一种通用类型 function,它可以接受回调 function,它可以执行任何操作打印任何内容并接收任何类型的变量。 Its possibilities are unlimited.它的可能性是无限的。

The pthread library requires this type of "universal function" behavior for running threads. pthread 库需要这种类型的“通用函数”行为来运行线程。 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.您必须传入一个您希望线程运行的 function,以及一个包含您需要 function 接收的任何 arguments 的void* To pass "multiple" args, pass them in via a ptr to a struct containing multiple args, as I demonstrated above.要传递“多个”args,请通过 ptr 将它们传递给包含多个 args 的结构,正如我在上面演示的那样。

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要在 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM